From: Erica Bugden Date: Wed, 21 Aug 2024 17:53:12 +0000 (-0400) Subject: debug-info: Compile as C++ X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=78ac3a7dcde59c85dfe6835e71eb7a10d78c1e82;p=babeltrace.git debug-info: Compile as C++ Justifications ============== Leave `crc32.h` and `crc32.c` as C code: The file is code external to the project and it is typical to never modify these files. However, when compiling alonside C++ code we must explicitly specify that it is C code so that the compiler knows to refer to function names with the non-mangled symbol name. Specifying that `crc32.h` is C in the file was less intrusive compared to translating the whole file to C++. Change-Id: I5e8823ceca994c035de6ebba5df22b2c3d11a02b Signed-off-by: Erica Bugden Reviewed-on: https://review.lttng.org/c/babeltrace/+/13225 Reviewed-by: Simon Marchi --- diff --git a/src/Makefile.am b/src/Makefile.am index 10d97d83..39d3ce5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,8 +243,8 @@ ctfser_libctfser_la_SOURCES = \ ctfser/ctfser.h fd_cache_libfd_cache_la_SOURCES = \ - fd-cache/fd-cache.c \ - fd-cache/fd-cache.h + fd-cache/fd-cache.cpp \ + fd-cache/fd-cache.hpp logging_liblogging_la_SOURCES = \ logging/comp-logging.h \ @@ -381,24 +381,24 @@ if ENABLE_DEBUG_INFO noinst_LTLIBRARIES += plugins/lttng-utils/debug-info/libdebug-info.la plugins_lttng_utils_debug_info_libdebug_info_la_SOURCES = \ - plugins/lttng-utils/debug-info/bin-info.c \ - plugins/lttng-utils/debug-info/bin-info.h \ + plugins/lttng-utils/debug-info/bin-info.cpp \ + plugins/lttng-utils/debug-info/bin-info.hpp \ plugins/lttng-utils/debug-info/crc32.c \ plugins/lttng-utils/debug-info/crc32.h \ - plugins/lttng-utils/debug-info/debug-info.c \ - plugins/lttng-utils/debug-info/debug-info.h \ - plugins/lttng-utils/debug-info/dwarf.c \ - plugins/lttng-utils/debug-info/dwarf.h \ - plugins/lttng-utils/debug-info/trace-ir-data-copy.c \ - plugins/lttng-utils/debug-info/trace-ir-data-copy.h \ - plugins/lttng-utils/debug-info/trace-ir-mapping.c \ - plugins/lttng-utils/debug-info/trace-ir-mapping.h \ - plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c \ - plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h \ - plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c \ - plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h \ - plugins/lttng-utils/debug-info/utils.c \ - plugins/lttng-utils/debug-info/utils.h + plugins/lttng-utils/debug-info/debug-info.cpp \ + plugins/lttng-utils/debug-info/debug-info.hpp \ + plugins/lttng-utils/debug-info/dwarf.cpp \ + plugins/lttng-utils/debug-info/dwarf.hpp \ + plugins/lttng-utils/debug-info/trace-ir-data-copy.cpp \ + plugins/lttng-utils/debug-info/trace-ir-data-copy.hpp \ + plugins/lttng-utils/debug-info/trace-ir-mapping.cpp \ + plugins/lttng-utils/debug-info/trace-ir-mapping.hpp \ + plugins/lttng-utils/debug-info/trace-ir-metadata-copy.cpp \ + plugins/lttng-utils/debug-info/trace-ir-metadata-copy.hpp \ + plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.cpp \ + plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.hpp \ + plugins/lttng-utils/debug-info/utils.cpp \ + plugins/lttng-utils/debug-info/utils.hpp plugins_lttng_utils_debug_info_libdebug_info_la_LIBADD = \ fd-cache/libfd-cache.la @@ -825,7 +825,7 @@ plugin_LTLIBRARIES += \ plugins/lttng-utils/babeltrace-plugin-lttng-utils.la plugins_lttng_utils_babeltrace_plugin_lttng_utils_la_SOURCES = \ - plugins/lttng-utils/plugin.c + plugins/lttng-utils/plugin.cpp plugins_lttng_utils_babeltrace_plugin_lttng_utils_la_LDFLAGS = \ $(AM_LDFLAGS) \ diff --git a/src/fd-cache/fd-cache.c b/src/fd-cache/fd-cache.c deleted file mode 100644 index f22e7eb5..00000000 --- a/src/fd-cache/fd-cache.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Francis Deslauriers - * - * Babeltrace - File descriptor cache - */ - -#define BT_LOG_OUTPUT_LEVEL (fdc->log_level) -#define BT_LOG_TAG "FD-CACHE" -#include "logging/log.h" - -#include -#include -#include -#include -#include - -#include "common/assert.h" -#include "fd-cache.h" - -struct file_key { - uint64_t dev; - uint64_t ino; -}; - -struct fd_handle_internal { - struct bt_fd_cache_handle fd_handle; - uint64_t ref_count; - struct file_key *key; -}; - -static -void fd_cache_handle_internal_destroy( - struct fd_handle_internal *internal_fd) -{ - if (!internal_fd) { - goto end; - } - - if (internal_fd->fd_handle.fd >= 0) { - close(internal_fd->fd_handle.fd); - internal_fd->fd_handle.fd = -1; - } - -end: - g_free(internal_fd); -} - -/* - * Using simple hash algorithm found on stackoverflow: - * https://stackoverflow.com/questions/664014/ - */ -static inline -uint64_t hash_uint64_t(uint64_t x) { - x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); - x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); - x = x ^ (x >> 31); - return x; -} - -static -guint file_key_hash(gconstpointer v) -{ - const struct file_key *fk = v; - return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino); -} - -static -gboolean file_key_equal(gconstpointer v1, gconstpointer v2) -{ - const struct file_key *fk1 = v1; - const struct file_key *fk2 = v2; - - return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino); -} - -static -void file_key_destroy(gpointer data) -{ - struct file_key *fk = data; - g_free(fk); -} - -int bt_fd_cache_init(struct bt_fd_cache *fdc, int log_level) -{ - int ret = 0; - - fdc->log_level = log_level; - fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal, - file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy); - if (!fdc->cache) { - ret = -1; - } - - return ret; -} - -void bt_fd_cache_fini(struct bt_fd_cache *fdc) -{ - if (!fdc->cache) { - goto end; - } - - /* - * All handle should have been removed for the hashtable at this point. - */ - BT_ASSERT(g_hash_table_size(fdc->cache) == 0); - g_hash_table_destroy(fdc->cache); - -end: - return; -} - -struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc, - const char *path) -{ - struct fd_handle_internal *fd_internal = NULL; - struct stat statbuf; - struct file_key fk; - int ret, fd = -1; - - ret = stat(path, &statbuf); - if (ret < 0) { - /* - * This is not necessarily an error as we sometimes try to open - * files to see if they exist. Log the error as DEBUG severity - * level. - */ - BT_LOGD_ERRNO("Failed to stat file", ": path=%s", path); - goto end; - } - - /* - * Use the device number and inode number to uniquely identify a file. - * Even if the file has the same path, it may have been replaced so we - * must open a new FD for it. This replacement of file is more likely - * to happen with a lttng-live source component. - */ - fk.dev = statbuf.st_dev; - fk.ino = statbuf.st_ino; - - fd_internal = g_hash_table_lookup(fdc->cache, &fk); - if (!fd_internal) { - struct file_key *file_key; - - fd = open(path, O_RDONLY); - if (fd < 0) { - BT_LOGE_ERRNO("Failed to open file", "path=%s", path); - goto error; - } - - fd_internal = g_new0(struct fd_handle_internal, 1); - if (!fd_internal) { - BT_LOGE_STR("Failed to allocate internal FD handle."); - goto error; - } - - file_key = g_new0(struct file_key, 1); - if (!fd_internal) { - BT_LOGE_STR("Failed to allocate file key."); - goto error; - } - - *file_key = fk; - - fd_internal->fd_handle.fd = fd; - fd_internal->ref_count = 0; - fd_internal->key = file_key; - - /* Insert the newly created fd handle. */ - g_hash_table_insert(fdc->cache, fd_internal->key, fd_internal); - } - - fd_internal->ref_count++; - goto end; - -error: - /* - * Close file descriptor if it was open() and we are currently on error - * path. - */ - if (fd != -1) { - ret = close(fd); - if (ret) { - BT_LOGE_ERRNO("Failed to close file descriptor", - ": fd=%i, path=%s", fd, path); - } - } - - fd_cache_handle_internal_destroy(fd_internal); - fd_internal = NULL; -end: - return (struct bt_fd_cache_handle *) fd_internal; -} - -void bt_fd_cache_put_handle(struct bt_fd_cache *fdc, - struct bt_fd_cache_handle *handle) -{ - struct fd_handle_internal *fd_internal; - - if (!handle) { - goto end; - } - - fd_internal = (struct fd_handle_internal *) handle; - - BT_ASSERT(fd_internal->ref_count > 0); - - if (fd_internal->ref_count > 1) { - fd_internal->ref_count--; - } else { - gboolean ret; - int close_ret; - - close_ret = close(fd_internal->fd_handle.fd); - if (close_ret == -1) { - BT_LOGE_ERRNO("Failed to close file descriptor", - ": fd=%d", fd_internal->fd_handle.fd); - } - ret = g_hash_table_remove(fdc->cache, fd_internal->key); - BT_ASSERT(ret); - } - -end: - return; -} diff --git a/src/fd-cache/fd-cache.cpp b/src/fd-cache/fd-cache.cpp new file mode 100644 index 00000000..4ccf41f9 --- /dev/null +++ b/src/fd-cache/fd-cache.cpp @@ -0,0 +1,229 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Francis Deslauriers + * + * Babeltrace - File descriptor cache + */ + +/* clang-format off */ + +#define BT_LOG_OUTPUT_LEVEL (fdc->log_level) +#define BT_LOG_TAG "FD-CACHE" +#include "logging/log.h" + +#include +#include +#include +#include +#include + +#include "common/assert.h" +#include "fd-cache.hpp" + +struct file_key { + uint64_t dev; + uint64_t ino; +}; + +struct fd_handle_internal { + struct bt_fd_cache_handle fd_handle; + uint64_t ref_count; + struct file_key *key; +}; + +static +void fd_cache_handle_internal_destroy( + struct fd_handle_internal *internal_fd) +{ + if (!internal_fd) { + goto end; + } + + if (internal_fd->fd_handle.fd >= 0) { + close(internal_fd->fd_handle.fd); + internal_fd->fd_handle.fd = -1; + } + +end: + g_free(internal_fd); +} + +/* + * Using simple hash algorithm found on stackoverflow: + * https://stackoverflow.com/questions/664014/ + */ +static inline +uint64_t hash_uint64_t(uint64_t x) { + x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); + x = x ^ (x >> 31); + return x; +} + +static +guint file_key_hash(gconstpointer v) +{ + const struct file_key *fk = static_cast(v); + return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino); +} + +static +gboolean file_key_equal(gconstpointer v1, gconstpointer v2) +{ + const struct file_key *fk1 = static_cast(v1); + const struct file_key *fk2 = static_cast(v2); + + return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino); +} + +static +void file_key_destroy(gpointer data) +{ + struct file_key *fk = static_cast(data); + g_free(fk); +} + +int bt_fd_cache_init(struct bt_fd_cache *fdc, int log_level) +{ + int ret = 0; + + fdc->log_level = log_level; + fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal, + file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy); + if (!fdc->cache) { + ret = -1; + } + + return ret; +} + +void bt_fd_cache_fini(struct bt_fd_cache *fdc) +{ + if (!fdc->cache) { + goto end; + } + + /* + * All handle should have been removed for the hashtable at this point. + */ + BT_ASSERT(g_hash_table_size(fdc->cache) == 0); + g_hash_table_destroy(fdc->cache); + +end: + return; +} + +struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc, + const char *path) +{ + struct fd_handle_internal *fd_internal = NULL; + struct stat statbuf; + struct file_key fk; + int ret, fd = -1; + + ret = stat(path, &statbuf); + if (ret < 0) { + /* + * This is not necessarily an error as we sometimes try to open + * files to see if they exist. Log the error as DEBUG severity + * level. + */ + BT_LOGD_ERRNO("Failed to stat file", ": path=%s", path); + goto end; + } + + /* + * Use the device number and inode number to uniquely identify a file. + * Even if the file has the same path, it may have been replaced so we + * must open a new FD for it. This replacement of file is more likely + * to happen with a lttng-live source component. + */ + fk.dev = statbuf.st_dev; + fk.ino = statbuf.st_ino; + + fd_internal = static_cast(g_hash_table_lookup(fdc->cache, &fk)); + if (!fd_internal) { + struct file_key *file_key; + + fd = open(path, O_RDONLY); + if (fd < 0) { + BT_LOGE_ERRNO("Failed to open file", "path=%s", path); + goto error; + } + + fd_internal = g_new0(struct fd_handle_internal, 1); + if (!fd_internal) { + BT_LOGE_STR("Failed to allocate internal FD handle."); + goto error; + } + + file_key = g_new0(struct file_key, 1); + if (!fd_internal) { + BT_LOGE_STR("Failed to allocate file key."); + goto error; + } + + *file_key = fk; + + fd_internal->fd_handle.fd = fd; + fd_internal->ref_count = 0; + fd_internal->key = file_key; + + /* Insert the newly created fd handle. */ + g_hash_table_insert(fdc->cache, fd_internal->key, fd_internal); + } + + fd_internal->ref_count++; + goto end; + +error: + /* + * Close file descriptor if it was open() and we are currently on error + * path. + */ + if (fd != -1) { + ret = close(fd); + if (ret) { + BT_LOGE_ERRNO("Failed to close file descriptor", + ": fd=%i, path=%s", fd, path); + } + } + + fd_cache_handle_internal_destroy(fd_internal); + fd_internal = NULL; +end: + return (struct bt_fd_cache_handle *) fd_internal; +} + +void bt_fd_cache_put_handle(struct bt_fd_cache *fdc, + struct bt_fd_cache_handle *handle) +{ + struct fd_handle_internal *fd_internal; + + if (!handle) { + goto end; + } + + fd_internal = (struct fd_handle_internal *) handle; + + BT_ASSERT(fd_internal->ref_count > 0); + + if (fd_internal->ref_count > 1) { + fd_internal->ref_count--; + } else { + gboolean ret; + int close_ret; + + close_ret = close(fd_internal->fd_handle.fd); + if (close_ret == -1) { + BT_LOGE_ERRNO("Failed to close file descriptor", + ": fd=%d", fd_internal->fd_handle.fd); + } + ret = g_hash_table_remove(fdc->cache, fd_internal->key); + BT_ASSERT(ret); + } + +end: + return; +} diff --git a/src/fd-cache/fd-cache.h b/src/fd-cache/fd-cache.h deleted file mode 100644 index a3593381..00000000 --- a/src/fd-cache/fd-cache.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Francis Deslauriers - * - * Babeltrace - File descriptor cache - */ - -#ifndef BABELTRACE_FD_CACHE_FD_CACHE_H -#define BABELTRACE_FD_CACHE_FD_CACHE_H - -#include - -struct bt_fd_cache_handle { - int fd; -}; - -struct bt_fd_cache { - int log_level; - GHashTable *cache; -}; - -static inline -int bt_fd_cache_handle_get_fd(struct bt_fd_cache_handle *handle) -{ - return handle->fd; -} - -int bt_fd_cache_init(struct bt_fd_cache *fdc, int log_level); - -void bt_fd_cache_fini(struct bt_fd_cache *fdc); - -struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc, - const char *path); - -void bt_fd_cache_put_handle(struct bt_fd_cache *fdc, - struct bt_fd_cache_handle *handle); - -#endif /* BABELTRACE_FD_CACHE_FD_CACHE_H */ diff --git a/src/fd-cache/fd-cache.hpp b/src/fd-cache/fd-cache.hpp new file mode 100644 index 00000000..34cdf2f8 --- /dev/null +++ b/src/fd-cache/fd-cache.hpp @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Francis Deslauriers + * + * Babeltrace - File descriptor cache + */ + +/* clang-format off */ + +#ifndef BABELTRACE_FD_CACHE_FD_CACHE_HPP +#define BABELTRACE_FD_CACHE_FD_CACHE_HPP + +#include + +struct bt_fd_cache_handle { + int fd; +}; + +struct bt_fd_cache { + int log_level; + GHashTable *cache; +}; + +static inline +int bt_fd_cache_handle_get_fd(struct bt_fd_cache_handle *handle) +{ + return handle->fd; +} + +int bt_fd_cache_init(struct bt_fd_cache *fdc, int log_level); + +void bt_fd_cache_fini(struct bt_fd_cache *fdc); + +struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc, + const char *path); + +void bt_fd_cache_put_handle(struct bt_fd_cache *fdc, + struct bt_fd_cache_handle *handle); + +#endif /* BABELTRACE_FD_CACHE_FD_CACHE_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/bin-info.c b/src/plugins/lttng-utils/debug-info/bin-info.c deleted file mode 100644 index 99127291..00000000 --- a/src/plugins/lttng-utils/debug-info/bin-info.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Babeltrace - Executable and Shared Object Debug Info Reader - * - * Copyright 2015 Antoine Busque - */ - -#define BT_COMP_LOG_SELF_COMP (bin->self_comp) -#define BT_LOG_OUTPUT_LEVEL (bin->log_level) -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/BIN-INFO" -#include "logging/comp-logging.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "common/common.h" - -#include "bin-info.h" -#include "crc32.h" -#include "dwarf.h" -#include "utils.h" - -/* - * An address printed in hex is at most 20 bytes (16 for 64-bits + - * leading 0x + optional leading '+' if addr is an offset + null - * character). - */ -#define ADDR_STR_LEN 20 -#define BUILD_ID_NOTE_NAME "GNU" - -int bin_info_init(bt_logging_level log_level, bt_self_component *self_comp) -{ - int ret = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) { - BT_COMP_LOG_CUR_LVL(BT_LOG_INFO, log_level, self_comp, - "ELF library initialization failed: %s.", - elf_errmsg(-1)); - ret = -1; - } - - return ret; -} - -struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path, - uint64_t low_addr, uint64_t memsz, bool is_pic, - const char *debug_info_dir, const char *target_prefix, - bt_logging_level log_level, bt_self_component *self_comp) -{ - struct bin_info *bin = NULL; - - BT_ASSERT(fdc); - - if (!path) { - goto error; - } - - bin = g_new0(struct bin_info, 1); - if (!bin) { - goto error; - } - - bin->log_level = log_level; - bin->self_comp = self_comp; - if (target_prefix) { - bin->elf_path = g_build_filename(target_prefix, path, NULL); - } else { - bin->elf_path = g_strdup(path); - } - - if (!bin->elf_path) { - goto error; - } - - if (debug_info_dir) { - bin->debug_info_dir = g_strdup(debug_info_dir); - if (!bin->debug_info_dir) { - goto error; - } - } - - bin->is_pic = is_pic; - bin->memsz = memsz; - bin->low_addr = low_addr; - bin->high_addr = bin->low_addr + bin->memsz; - bin->build_id = NULL; - bin->build_id_len = 0; - bin->file_build_id_matches = false; - bin->fd_cache = fdc; - - return bin; - -error: - bin_info_destroy(bin); - return NULL; -} - -void bin_info_destroy(struct bin_info *bin) -{ - if (!bin) { - return; - } - - dwarf_end(bin->dwarf_info); - - g_free(bin->debug_info_dir); - g_free(bin->elf_path); - g_free(bin->dwarf_path); - g_free(bin->build_id); - g_free(bin->dbg_link_filename); - - elf_end(bin->elf_file); - - bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle); - bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle); - - g_free(bin); -} - -/** - * Initialize the ELF file for a given executable. - * - * @param bin bin_info instance - * @returns 0 on success, negative value on error. - */ -static -int bin_info_set_elf_file(struct bin_info *bin) -{ - struct bt_fd_cache_handle *elf_handle = NULL; - Elf *elf_file = NULL; - int ret; - - BT_ASSERT(bin); - - elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path); - if (!elf_handle) { - BT_COMP_LOGI("Failed to open %s", bin->elf_path); - goto error; - } - bin->elf_handle = elf_handle; - - elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle), - ELF_C_READ, NULL); - if (!elf_file) { - BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp, - "elf_begin failed: %s", elf_errmsg(-1)); - goto error; - } - - bin->elf_file = elf_file; - - if (elf_kind(elf_file) != ELF_K_ELF) { - BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp, - "Error: %s is not an ELF object", bin->elf_path); - goto error; - } - - - ret = 0; - goto end; - -error: - bt_fd_cache_put_handle(bin->fd_cache, elf_handle); - elf_end(elf_file); - ret = -1; - -end: - return ret; -} - -/** - * From a note section data struct, check if it is a build id note. - * - * @param note_data Pointer to a note section - * - * @returns 1 on match, 0 if `buf` does not contain a - * valid build id note - */ -static -int is_build_id_note_section(Elf_Data *note_data) -{ - size_t name_offset, desc_offset; - GElf_Nhdr note_header; - int ret = 0; - - /* - * Discard the return value as it contains the size of the note section - * and we don't need it. - */ - (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, - &desc_offset); - - /* - * Check the note name length. The name_sz field includes the - * terminating null byte. - */ - if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) { - goto invalid; - } - - /* Check the note type. */ - if (note_header.n_type != NT_GNU_BUILD_ID) { - goto invalid; - } - - /* Check the note name. */ - if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME, - note_header.n_namesz) != 0) { - goto invalid; - } - - ret = 1; - -invalid: - return ret; -} - -/** - * From a build id note section data struct, check if the build id it contains - * is identical to the build id passed as parameter. - * - * @param note_data Pointer to the file build id note section. - * @param build_id Pointer to a build id to compare to. - * @param build_id_len length of the build id. - * - * @returns 1 on match, 0 otherwise. - */ -static -int is_build_id_note_section_matching(Elf_Data *note_data, - uint8_t *build_id, size_t build_id_len) -{ - size_t name_offset, desc_offset; - GElf_Nhdr note_header; - - if (build_id_len <= 0) { - goto end; - } - - /* - * Discard the return value as it contains the size of the note section - * and we don't need it. - */ - (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, - &desc_offset); - - /* - * Compare the binary build id with the supplied build id. - */ - if (memcmp(build_id, note_data->d_buf + desc_offset, - build_id_len) == 0) { - return 1; - } -end: - return 0; -} - -/** - * Checks if the build id stored in `bin` (bin->build_id) is matching the build - * id of the ondisk file (bin->elf_file). - * - * @param bin bin_info instance - * @param build_id build id to compare ot the on disk file - * @param build_id_len length of the build id - * - * @returns 1 on if the build id of stored in `bin` matches - * the build id of the ondisk file. - * 0 on if they are different or an error occurred. - */ -static -int is_build_id_matching(struct bin_info *bin) -{ - int ret, is_build_id, is_matching = 0; - Elf_Scn *curr_section = NULL, *next_section = NULL; - GElf_Shdr curr_section_hdr; - - if (!bin->build_id) { - goto error; - } - - /* Set ELF file if it hasn't been accessed yet. */ - if (!bin->elf_file) { - ret = bin_info_set_elf_file(bin); - if (ret) { - /* Failed to set ELF file. */ - goto error; - } - } - - next_section = elf_nextscn(bin->elf_file, curr_section); - if (!next_section) { - goto error; - } - - while (next_section) { - Elf_Data *note_data = NULL; - - curr_section = next_section; - next_section = elf_nextscn(bin->elf_file, curr_section); - - if (!gelf_getshdr(curr_section, &curr_section_hdr)) { - goto error; - } - - if (curr_section_hdr.sh_type != SHT_NOTE) { - continue; - } - - /* - * elf_getdata() translates the data to native byte order. - */ - note_data = elf_getdata(curr_section, NULL); - if (!note_data) { - goto error; - } - - /* Check if the note is of the build-id type. */ - is_build_id = is_build_id_note_section(note_data); - if (!is_build_id) { - continue; - } - - /* - * Compare the build id of the on-disk file and - * the build id recorded in the trace. - */ - is_matching = is_build_id_note_section_matching( - note_data, bin->build_id, bin->build_id_len); - if (!is_matching) { - break; - } - } -error: - return is_matching; -} - -int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, - size_t build_id_len) -{ - if (!bin || !build_id) { - goto error; - } - - /* Free any previously set build id. */ - g_free(bin->build_id); - - /* Set the build id. */ - bin->build_id = g_new0(uint8_t, build_id_len); - if (!bin->build_id) { - goto error; - } - - memcpy(bin->build_id, build_id, build_id_len); - bin->build_id_len = build_id_len; - - /* - * Check if the file found on the file system has the same build id - * that what was recorded in the trace. - */ - bin->file_build_id_matches = is_build_id_matching(bin); - if (!bin->file_build_id_matches) { - BT_COMP_LOGI_STR("Supplied Build ID does not match Build ID of the " - "binary or library found on the file system."); - goto error; - } - - /* - * Reset the is_elf_only flag in case it had been set - * previously, because we might find separate debug info using - * the new build id information. - */ - bin->is_elf_only = false; - - return 0; - -error: - return -1; -} - -int bin_info_set_debug_link(struct bin_info *bin, const char *filename, - uint32_t crc) -{ - if (!bin || !filename) { - goto error; - } - - bin->dbg_link_filename = g_strdup(filename); - if (!bin->dbg_link_filename) { - goto error; - } - - bin->dbg_link_crc = crc; - - /* - * Reset the is_elf_only flag in case it had been set - * previously, because we might find separate debug info using - * the new build id information. - */ - bin->is_elf_only = false; - - return 0; - -error: - - return -1; -} - -/** - * Tries to read DWARF info from the location given by path, and - * attach it to the given bin_info instance if it exists. - * - * @param bin bin_info instance for which to set DWARF info - * @param path Presumed location of the DWARF info - * @returns 0 on success, negative value on failure - */ -static -int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path) -{ - int ret = 0; - struct bt_fd_cache_handle *dwarf_handle = NULL; - struct bt_dwarf_cu *cu = NULL; - Dwarf *dwarf_info = NULL; - - if (!bin || !path) { - goto error; - } - - dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path); - if (!dwarf_handle) { - goto error; - } - - dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle), - DWARF_C_READ); - if (!dwarf_info) { - goto error; - } - - /* - * Check if the dwarf info has any CU. If not, the - * executable's object file contains no DWARF info. - */ - cu = bt_dwarf_cu_create(dwarf_info); - if (!cu) { - goto error; - } - - ret = bt_dwarf_cu_next(cu); - if (ret) { - goto error; - } - - bin->dwarf_handle = dwarf_handle; - bin->dwarf_path = g_strdup(path); - if (!bin->dwarf_path) { - goto error; - } - bin->dwarf_info = dwarf_info; - free(cu); - - return 0; - -error: - if (bin) { - bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle); - } - dwarf_end(dwarf_info); - g_free(dwarf_info); - free(cu); - - return -1; -} - -/** - * Try to set the dwarf_info for a given bin_info instance via the - * build ID method. - * - * @param bin bin_info instance for which to retrieve the - * DWARF info via build ID - * @returns 0 on success (i.e. dwarf_info set), -1 on failure - */ -static -int bin_info_set_dwarf_info_build_id(struct bin_info *bin) -{ - int i = 0, ret = 0; - char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL; - const char *dbg_dir = NULL; - size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len; - - if (!bin || !bin->build_id) { - goto error; - } - - dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; - - /* - * The prefix dir is the first byte of the build id, represented in - * lowercase hex as two characters per byte, +1 for '\0'. - */ - build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1); - if (!build_id_prefix_dir) { - goto error; - } - g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]); - - /* - * The build id file is the remaining bytes of the build id, - * represented in lowercase hex, as two characters per byte. - */ - build_id_char_len = (2 * (bin->build_id_len - 1)); - - /* To which the build id suffix is added, +1 for '\0'. */ - build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1; - - /* - * The resulting filename string is the concatenation of the - * hex build id and the suffix. - */ - build_id_file_len = build_id_char_len + build_id_suffix_char_len; - build_id_file = g_new0(gchar, build_id_file_len); - if (!build_id_file) { - goto error; - } - - /* - * For each byte, starting at offset 1, append two characters - * in lowercase hex. - */ - for (i = 1; i < bin->build_id_len; ++i) { - int path_idx = 2 * (i - 1); - - g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); - } - /* Append the suffix to the generated string, including the '\0'. */ - g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len, - BUILD_ID_SUFFIX); - - path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL); - if (!path) { - goto error; - } - - ret = bin_info_set_dwarf_info_from_path(bin, path); - if (ret) { - goto error; - } - - goto end; - -error: - ret = -1; -end: - g_free(build_id_prefix_dir); - g_free(build_id_file); - g_free(path); - - return ret; -} - -/** - * Tests whether the file located at path exists and has the expected - * checksum. - * - * This predicate is used when looking up separate debug info via the - * GNU debuglink method. The expected crc can be found .gnu_debuglink - * section in the original ELF file, along with the filename for the - * file containing the debug info. - * - * @param path Full path at which to look for the debug file - * @param crc Expected checksum for the debug file - * @returns 1 if the file exists and has the correct checksum, - * 0 otherwise - */ -static -int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc) -{ - int ret = 0; - struct bt_fd_cache_handle *debug_handle = NULL; - uint32_t _crc = 0; - - if (!path) { - goto end; - } - - debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path); - if (!debug_handle) { - goto end; - } - - ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc); - if (ret) { - ret = 0; - goto end; - } - - ret = (crc == _crc); - -end: - bt_fd_cache_put_handle(bin->fd_cache, debug_handle); - return ret; -} - -/** - * Try to set the dwarf_info for a given bin_info instance via the - * debug-link method. - * - * @param bin bin_info instance for which to retrieve the - * DWARF info via debug link - * @returns 0 on success (i.e. dwarf_info set), -1 on failure - */ -static -int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) -{ - int ret = 0; - const gchar *dbg_dir = NULL; - gchar *bin_dir = NULL, *path = NULL; - - if (!bin || !bin->dbg_link_filename) { - goto error; - } - - dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; - bin_dir = g_path_get_dirname(bin->elf_path); - - /* First look in the executable's dir */ - path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL); - - if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { - goto found; - } - - /* If not found, look in .debug subdir */ - g_free(path); - path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); - - if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { - goto found; - } - - /* Lastly, look under the global debug directory */ - g_free(path); - - path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); - if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { - goto found; - } - -error: - ret = -1; -end: - g_free(bin_dir); - g_free(path); - - return ret; - -found: - ret = bin_info_set_dwarf_info_from_path(bin, path); - if (ret) { - goto error; - } - - goto end; -} - -/** - * Initialize the DWARF info for a given executable. - * - * @param bin bin_info instance - * @returns 0 on success, negative value on failure - */ -static -int bin_info_set_dwarf_info(struct bin_info *bin) -{ - int ret = 0; - - if (!bin) { - ret = -1; - goto end; - } - - /* First try to set the DWARF info from the ELF file */ - ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path); - if (!ret) { - goto end; - } - - /* - * If that fails, try to find separate debug info via build ID - * and debug link. - */ - ret = bin_info_set_dwarf_info_build_id(bin); - if (!ret) { - goto end; - } - - ret = bin_info_set_dwarf_info_debug_link(bin); - if (!ret) { - goto end; - } - -end: - return ret; -} - -void source_location_destroy(struct source_location *src_loc) -{ - if (!src_loc) { - return; - } - - free(src_loc->filename); - g_free(src_loc); -} - -/** - * Append a string representation of an address offset to an existing - * string. - * - * On success, the out parameter `result` will contain the base string - * followed by the offset string of the form "+0x1234". On failure, - * `result` remains unchanged. - * - * @param base_str The string to which to append an offset string - * @param low_addr The lower virtual memory address, the base from - * which the offset is computed - * @param high_addr The higher virtual memory address - * @param result Out parameter, the base string followed by the - * offset string - * @returns 0 on success, -1 on failure - */ -static -int bin_info_append_offset_str(const char *base_str, uint64_t low_addr, - uint64_t high_addr, char **result) -{ - uint64_t offset; - char *_result = NULL; - - if (!base_str || !result) { - goto error; - } - - offset = high_addr - low_addr; - - _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset); - if (!_result) { - goto error; - } - *result = _result; - - return 0; - -error: - free(_result); - return -1; -} - -/** - * Try to find the symbol closest to an address within a given ELF - * section. - * - * Only function symbols are taken into account. The symbol's address - * must precede `addr`. A symbol with a closer address might exist - * after `addr` but is irrelevant because it cannot encompass `addr`. - * - * On success, if found, the out parameters `sym` and `shdr` are - * set. On failure or if none are found, they remain unchanged. - * - * @param scn ELF section in which to look for the address - * @param addr Virtual memory address for which to find the - * nearest function symbol - * @param sym Out parameter, the nearest function symbol - * @param shdr Out parameter, the section header for scn - * @returns 0 on success, -1 on failure - */ -static -int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr, - GElf_Sym **sym, GElf_Shdr **shdr) -{ - int i; - size_t symbol_count; - Elf_Data *data = NULL; - GElf_Shdr *_shdr = NULL; - GElf_Sym *nearest_sym = NULL; - - if (!scn || !sym || !shdr) { - goto error; - } - - _shdr = g_new0(GElf_Shdr, 1); - if (!_shdr) { - goto error; - } - - _shdr = gelf_getshdr(scn, _shdr); - if (!_shdr) { - goto error; - } - - if (_shdr->sh_type != SHT_SYMTAB) { - /* - * We are only interested in symbol table (symtab) - * sections, skip this one. - */ - goto end; - } - - data = elf_getdata(scn, NULL); - if (!data) { - goto error; - } - - symbol_count = _shdr->sh_size / _shdr->sh_entsize; - - for (i = 0; i < symbol_count; ++i) { - GElf_Sym *cur_sym = NULL; - - cur_sym = g_new0(GElf_Sym, 1); - if (!cur_sym) { - goto error; - } - cur_sym = gelf_getsym(data, i, cur_sym); - if (!cur_sym) { - goto error; - } - if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) { - /* We're only interested in the functions. */ - g_free(cur_sym); - continue; - } - - if (cur_sym->st_value <= addr && - (!nearest_sym || - cur_sym->st_value > nearest_sym->st_value)) { - g_free(nearest_sym); - nearest_sym = cur_sym; - } else { - g_free(cur_sym); - } - } - -end: - if (nearest_sym) { - *sym = nearest_sym; - *shdr = _shdr; - } else { - g_free(_shdr); - } - - return 0; - -error: - g_free(nearest_sym); - g_free(_shdr); - return -1; -} - -/** - * Get the name of the function containing a given address within an - * executable using ELF symbols. - * - * The function name is in fact the name of the nearest ELF symbol, - * followed by the offset in bytes between the address and the symbol - * (in hex), separated by a '+' character. - * - * If found, the out parameter `func_name` is set on success. On failure, - * it remains unchanged. - * - * @param bin bin_info instance for the executable containing - * the address - * @param addr Virtual memory address for which to find the - * function name - * @param func_name Out parameter, the function name - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr, - char **func_name) -{ - /* - * TODO (possible optimisation): if an ELF has no symtab - * section, it has been stripped. Therefore, it would be wise - * to store a flag indicating the stripped status after the - * first iteration to prevent subsequent ones. - */ - int ret = 0; - Elf_Scn *scn = NULL; - GElf_Sym *sym = NULL; - GElf_Shdr *shdr = NULL; - char *sym_name = NULL; - - /* Set ELF file if it hasn't been accessed yet. */ - if (!bin->elf_file) { - ret = bin_info_set_elf_file(bin); - if (ret) { - /* Failed to set ELF file. */ - goto error; - } - } - - scn = elf_nextscn(bin->elf_file, scn); - if (!scn) { - goto error; - } - - while (scn && !sym) { - ret = bin_info_get_nearest_symbol_from_section( - scn, addr, &sym, &shdr); - if (ret) { - goto error; - } - - scn = elf_nextscn(bin->elf_file, scn); - } - - if (sym) { - sym_name = elf_strptr(bin->elf_file, shdr->sh_link, - sym->st_name); - if (!sym_name) { - goto error; - } - - ret = bin_info_append_offset_str(sym_name, sym->st_value, addr, - func_name); - if (ret) { - goto error; - } - } - - g_free(shdr); - g_free(sym); - return 0; - -error: - g_free(shdr); - g_free(sym); - return ret; -} - -/** - * Get the name of the function containing a given address within a - * given compile unit (CU). - * - * If found, the out parameter `func_name` is set on success. On - * failure, it remains unchanged. - * - * @param cu bt_dwarf_cu instance which may contain the address - * @param addr Virtual memory address for which to find the - * function name - * @param func_name Out parameter, the function name - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr, - char **func_name) -{ - int ret = 0; - bool found = false; - struct bt_dwarf_die *die = NULL; - - if (!cu || !func_name) { - goto error; - } - - die = bt_dwarf_die_create(cu); - if (!die) { - goto error; - } - - while (bt_dwarf_die_next(die) == 0) { - int tag; - - ret = bt_dwarf_die_get_tag(die, &tag); - if (ret) { - goto error; - } - - if (tag == DW_TAG_subprogram) { - ret = bt_dwarf_die_contains_addr(die, addr, &found); - if (ret) { - goto error; - } - - if (found) { - break; - } - } - } - - if (found) { - uint64_t low_addr = 0; - char *die_name = NULL; - - ret = bt_dwarf_die_get_name(die, &die_name); - if (ret) { - goto error; - } - - ret = dwarf_lowpc(die->dwarf_die, &low_addr); - if (ret) { - free(die_name); - goto error; - } - - ret = bin_info_append_offset_str(die_name, low_addr, addr, - func_name); - free(die_name); - if (ret) { - goto error; - } - } - - bt_dwarf_die_destroy(die); - return 0; - -error: - bt_dwarf_die_destroy(die); - return -1; -} - -/** - * Get the name of the function containing a given address within an - * executable using DWARF debug info. - * - * If found, the out parameter `func_name` is set on success. On - * failure, it remains unchanged. - * - * @param bin bin_info instance for the executable containing - * the address - * @param addr Virtual memory address for which to find the - * function name - * @param func_name Out parameter, the function name - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr, - char **func_name) -{ - int ret = 0; - char *_func_name = NULL; - struct bt_dwarf_cu *cu = NULL; - - if (!bin || !func_name) { - goto error; - } - - cu = bt_dwarf_cu_create(bin->dwarf_info); - if (!cu) { - goto error; - } - - while (bt_dwarf_cu_next(cu) == 0) { - ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name); - if (ret) { - goto error; - } - - if (_func_name) { - break; - } - } - - if (_func_name) { - *func_name = _func_name; - } else { - goto error; - } - - bt_dwarf_cu_destroy(cu); - return 0; - -error: - bt_dwarf_cu_destroy(cu); - return -1; -} - -int bin_info_lookup_function_name(struct bin_info *bin, - uint64_t addr, char **func_name) -{ - int ret = 0; - char *_func_name = NULL; - - if (!bin || !func_name) { - goto error; - } - - /* - * If the bin_info has a build id but it does not match the build id - * that was found on the file system, return an error. - */ - if (bin->build_id && !bin->file_build_id_matches) { - goto error; - } - - /* Set DWARF info if it hasn't been accessed yet. */ - if (!bin->dwarf_info && !bin->is_elf_only) { - ret = bin_info_set_dwarf_info(bin); - if (ret) { - BT_COMP_LOGI_STR("Failed to set bin dwarf info, falling " - "back to ELF lookup."); - /* Failed to set DWARF info, fallback to ELF. */ - bin->is_elf_only = true; - } - } - - if (!bin_info_has_address(bin, addr)) { - goto error; - } - - /* - * Addresses in ELF and DWARF are relative to base address for - * PIC, so make the address argument relative too if needed. - */ - if (bin->is_pic) { - addr -= bin->low_addr; - } - - if (bin->is_elf_only) { - ret = bin_info_lookup_elf_function_name(bin, addr, - &_func_name); - if (ret) { - BT_COMP_LOGI("Failed to lookup function name (ELF): " - "ret=%d", ret); - } - } else { - ret = bin_info_lookup_dwarf_function_name(bin, addr, - &_func_name); - if (ret) { - BT_COMP_LOGI("Failed to lookup function name (DWARF): " - "ret=%d", ret); - } - } - - *func_name = _func_name; - return 0; - -error: - return -1; -} - -int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc) -{ - gchar *_bin_loc = NULL; - - if (!bin || !bin_loc) { - goto error; - } - - /* - * If the bin_info has a build id but it does not match the build id - * that was found on the file system, return an error. - */ - if (bin->build_id && !bin->file_build_id_matches) { - goto error; - } - - if (bin->is_pic) { - addr -= bin->low_addr; - _bin_loc = g_strdup_printf("+%#0" PRIx64, addr); - } else { - _bin_loc = g_strdup_printf("@%#0" PRIx64, addr); - } - - if (!_bin_loc) { - goto error; - } - - *bin_loc = _bin_loc; - return 0; - -error: - return -1; -} - -/** - * Predicate used to determine whether the children of a given DIE - * contain a specific address. - * - * More specifically, the parameter `die` is expected to be a - * subprogram (function) DIE, and this predicate tells whether any - * subroutines are inlined within this function and would contain - * `addr`. - * - * On success, the out parameter `contains` is set with the boolean - * value indicating whether the DIE's range covers `addr`. On failure, - * it remains unchanged. - * - * Do note that this function advances the position of `die`. If the - * address is found within one of its children, `die` will be pointing - * to that child upon returning from the function, allowing to extract - * the information deemed necessary. - * - * @param die The parent DIE in whose children the address will be - * looked for - * @param addr The address for which to look for in the DIEs - * @param contains Out parameter, true if addr is contained, - * false if not - * @returns Returns 0 on success, -1 on failure - */ -static -int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains) -{ - int ret = 0; - bool _contains = false; - - if (!die) { - goto error; - } - - ret = bt_dwarf_die_child(die); - if (ret) { - goto error; - } - - do { - ret = bt_dwarf_die_contains_addr(die, addr, &_contains); - if (ret) { - goto error; - } - - if (_contains) { - /* - * The address is within the range of the current DIE - * or its children. - */ - int tag; - - ret = bt_dwarf_die_get_tag(die, &tag); - if (ret) { - goto error; - } - - if (tag == DW_TAG_inlined_subroutine) { - /* Found the tracepoint. */ - goto end; - } - - if (bt_dwarf_die_has_children(die)) { - /* - * Look for the address in the children DIEs. - */ - ret = bt_dwarf_die_child(die); - if (ret) { - goto error; - } - } - } - } while (bt_dwarf_die_next(die) == 0); - -end: - *contains = _contains; - return 0; - -error: - return -1; -} - -/** - * Lookup the source location for a given address within a CU, making - * the assumption that it is contained within an inline routine in a - * function. - * - * @param cu bt_dwarf_cu instance in which to look for the address - * @param addr The address for which to look for - * @param src_loc Out parameter, the source location (filename and - * line number) for the address - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr, - struct source_location **src_loc) -{ - int ret = 0; - bool found = false; - struct bt_dwarf_die *die = NULL; - struct source_location *_src_loc = NULL; - - if (!cu || !src_loc) { - goto error; - } - - die = bt_dwarf_die_create(cu); - if (!die) { - goto error; - } - - while (bt_dwarf_die_next(die) == 0) { - int tag; - - ret = bt_dwarf_die_get_tag(die, &tag); - if (ret) { - goto error; - } - - if (tag == DW_TAG_subprogram) { - bool contains = false; - - ret = bt_dwarf_die_contains_addr(die, addr, &contains); - if (ret) { - goto error; - } - - if (contains) { - /* - * Try to find an inlined subroutine - * child of this DIE containing addr. - */ - ret = bin_info_child_die_has_address(die, addr, - &found); - if(ret) { - goto error; - } - - goto end; - } - } - } - -end: - if (found) { - char *filename = NULL; - uint64_t line_no; - - _src_loc = g_new0(struct source_location, 1); - if (!_src_loc) { - goto error; - } - - ret = bt_dwarf_die_get_call_file(die, &filename); - if (ret) { - goto error; - } - ret = bt_dwarf_die_get_call_line(die, &line_no); - if (ret) { - free(filename); - goto error; - } - - _src_loc->filename = filename; - _src_loc->line_no = line_no; - *src_loc = _src_loc; - } - - bt_dwarf_die_destroy(die); - return 0; - -error: - source_location_destroy(_src_loc); - bt_dwarf_die_destroy(die); - return -1; -} - -/** - * Lookup the source location for a given address within a CU, - * assuming that it is contained within an inlined function. - * - * A source location can be found regardless of inlining status for - * this method, but in the case of an inlined function, the returned - * source location will point not to the callsite but rather to the - * definition site of the inline function. - * - * @param cu bt_dwarf_cu instance in which to look for the address - * @param addr The address for which to look for - * @param src_loc Out parameter, the source location (filename and - * line number) for the address. Set only if the address - * is found and resolved successfully - * - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, - struct source_location **src_loc) -{ - struct source_location *_src_loc = NULL; - struct bt_dwarf_die *die = NULL; - const char *filename = NULL; - Dwarf_Line *line = NULL; - Dwarf_Addr line_addr; - int ret = 0, line_no; - - if (!cu || !src_loc) { - goto error; - } - - die = bt_dwarf_die_create(cu); - if (!die) { - goto error; - } - - line = dwarf_getsrc_die(die->dwarf_die, addr); - if (!line) { - /* This is not an error. The caller needs to keep looking. */ - goto end; - } - - ret = dwarf_lineaddr(line, &line_addr); - if (ret) { - goto error; - } - - filename = dwarf_linesrc(line, NULL, NULL); - if (!filename) { - goto error; - } - - if (addr == line_addr) { - _src_loc = g_new0(struct source_location, 1); - if (!_src_loc) { - goto error; - } - - ret = dwarf_lineno(line, &line_no); - if (ret) { - goto error; - } - - _src_loc->line_no = line_no; - _src_loc->filename = g_strdup(filename); - } - - if (_src_loc) { - *src_loc = _src_loc; - } - - goto end; - -error: - source_location_destroy(_src_loc); - ret = -1; -end: - bt_dwarf_die_destroy(die); - return ret; -} - -/** - * Get the source location (file name and line number) for a given - * address within a compile unit (CU). - * - * On success, the out parameter `src_loc` is set if found. On - * failure, it remains unchanged. - * - * @param cu bt_dwarf_cu instance for the compile unit which - * may contain the address - * @param addr Virtual memory address for which to find the - * source location - * @param src_loc Out parameter, the source location - * @returns 0 on success, -1 on failure - */ -static -int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr, - struct source_location **src_loc) -{ - int ret = 0; - struct source_location *_src_loc = NULL; - - if (!cu || !src_loc) { - goto error; - } - - ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc); - if (ret) { - goto error; - } - - if (_src_loc) { - goto end; - } - - ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc); - if (ret) { - goto error; - } - - if (_src_loc) { - goto end; - } - -end: - if (_src_loc) { - *src_loc = _src_loc; - } - - return 0; - -error: - source_location_destroy(_src_loc); - return -1; -} - -int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr, - struct source_location **src_loc) -{ - struct bt_dwarf_cu *cu = NULL; - struct source_location *_src_loc = NULL; - - if (!bin || !src_loc) { - goto error; - } - - /* - * If the bin_info has a build id but it does not match the build id - * that was found on the file system, return an error. - */ - if (bin->build_id && !bin->file_build_id_matches) { - goto error; - } - - /* Set DWARF info if it hasn't been accessed yet. */ - if (!bin->dwarf_info && !bin->is_elf_only) { - if (bin_info_set_dwarf_info(bin)) { - /* Failed to set DWARF info. */ - bin->is_elf_only = true; - } - } - - if (bin->is_elf_only) { - /* We cannot lookup source location without DWARF info. */ - goto error; - } - - if (!bin_info_has_address(bin, addr)) { - goto error; - } - - /* - * Addresses in ELF and DWARF are relative to base address for - * PIC, so make the address argument relative too if needed. - */ - if (bin->is_pic) { - addr -= bin->low_addr; - } - - cu = bt_dwarf_cu_create(bin->dwarf_info); - if (!cu) { - goto error; - } - - while (bt_dwarf_cu_next(cu) == 0) { - int ret; - - ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc); - if (ret) { - goto error; - } - - if (_src_loc) { - break; - } - } - - bt_dwarf_cu_destroy(cu); - if (_src_loc) { - *src_loc = _src_loc; - } - - return 0; - -error: - source_location_destroy(_src_loc); - bt_dwarf_cu_destroy(cu); - return -1; -} diff --git a/src/plugins/lttng-utils/debug-info/bin-info.cpp b/src/plugins/lttng-utils/debug-info/bin-info.cpp new file mode 100644 index 00000000..8f9dfea5 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/bin-info.cpp @@ -0,0 +1,1574 @@ +/* + * SPDX-License-Identifier: MIT + * + * Babeltrace - Executable and Shared Object Debug Info Reader + * + * Copyright 2015 Antoine Busque + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP (bin->self_comp) +#define BT_LOG_OUTPUT_LEVEL (bin->log_level) +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/BIN-INFO" +#include "logging/comp-logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common/common.h" + +#include "bin-info.hpp" +#include "crc32.h" +#include "dwarf.hpp" +#include "utils.hpp" + +/* + * An address printed in hex is at most 20 bytes (16 for 64-bits + + * leading 0x + optional leading '+' if addr is an offset + null + * character). + */ +#define ADDR_STR_LEN 20 +#define BUILD_ID_NOTE_NAME "GNU" + +int bin_info_init(bt_logging_level log_level, bt_self_component *self_comp) +{ + int ret = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) { + BT_COMP_LOG_CUR_LVL(BT_LOG_INFO, log_level, self_comp, + "ELF library initialization failed: %s.", + elf_errmsg(-1)); + ret = -1; + } + + return ret; +} + +struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path, + uint64_t low_addr, uint64_t memsz, bool is_pic, + const char *debug_info_dir, const char *target_prefix, + bt_logging_level log_level, bt_self_component *self_comp) +{ + struct bin_info *bin = NULL; + + BT_ASSERT(fdc); + + if (!path) { + goto error; + } + + bin = g_new0(struct bin_info, 1); + if (!bin) { + goto error; + } + + bin->log_level = log_level; + bin->self_comp = self_comp; + if (target_prefix) { + bin->elf_path = g_build_filename(target_prefix, path, NULL); + } else { + bin->elf_path = g_strdup(path); + } + + if (!bin->elf_path) { + goto error; + } + + if (debug_info_dir) { + bin->debug_info_dir = g_strdup(debug_info_dir); + if (!bin->debug_info_dir) { + goto error; + } + } + + bin->is_pic = is_pic; + bin->memsz = memsz; + bin->low_addr = low_addr; + bin->high_addr = bin->low_addr + bin->memsz; + bin->build_id = NULL; + bin->build_id_len = 0; + bin->file_build_id_matches = false; + bin->fd_cache = fdc; + + return bin; + +error: + bin_info_destroy(bin); + return NULL; +} + +void bin_info_destroy(struct bin_info *bin) +{ + if (!bin) { + return; + } + + dwarf_end(bin->dwarf_info); + + g_free(bin->debug_info_dir); + g_free(bin->elf_path); + g_free(bin->dwarf_path); + g_free(bin->build_id); + g_free(bin->dbg_link_filename); + + elf_end(bin->elf_file); + + bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle); + bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle); + + g_free(bin); +} + +/** + * Initialize the ELF file for a given executable. + * + * @param bin bin_info instance + * @returns 0 on success, negative value on error. + */ +static +int bin_info_set_elf_file(struct bin_info *bin) +{ + struct bt_fd_cache_handle *elf_handle = NULL; + Elf *elf_file = NULL; + int ret; + + BT_ASSERT(bin); + + elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path); + if (!elf_handle) { + BT_COMP_LOGI("Failed to open %s", bin->elf_path); + goto error; + } + bin->elf_handle = elf_handle; + + elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle), + ELF_C_READ, NULL); + if (!elf_file) { + BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp, + "elf_begin failed: %s", elf_errmsg(-1)); + goto error; + } + + bin->elf_file = elf_file; + + if (elf_kind(elf_file) != ELF_K_ELF) { + BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp, + "Error: %s is not an ELF object", bin->elf_path); + goto error; + } + + + ret = 0; + goto end; + +error: + bt_fd_cache_put_handle(bin->fd_cache, elf_handle); + elf_end(elf_file); + ret = -1; + +end: + return ret; +} + +/** + * From a note section data struct, check if it is a build id note. + * + * @param note_data Pointer to a note section + * + * @returns 1 on match, 0 if `buf` does not contain a + * valid build id note + */ +static +int is_build_id_note_section(Elf_Data *note_data) +{ + size_t name_offset, desc_offset; + GElf_Nhdr note_header; + int ret = 0; + + /* + * Discard the return value as it contains the size of the note section + * and we don't need it. + */ + (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, + &desc_offset); + + /* + * Check the note name length. The name_sz field includes the + * terminating null byte. + */ + if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) { + goto invalid; + } + + /* Check the note type. */ + if (note_header.n_type != NT_GNU_BUILD_ID) { + goto invalid; + } + + /* Check the note name. */ + if (memcmp(static_cast(note_data->d_buf) + name_offset, BUILD_ID_NOTE_NAME, + note_header.n_namesz) != 0) { + goto invalid; + } + + ret = 1; + +invalid: + return ret; +} + +/** + * From a build id note section data struct, check if the build id it contains + * is identical to the build id passed as parameter. + * + * @param note_data Pointer to the file build id note section. + * @param build_id Pointer to a build id to compare to. + * @param build_id_len length of the build id. + * + * @returns 1 on match, 0 otherwise. + */ +static +int is_build_id_note_section_matching(Elf_Data *note_data, + uint8_t *build_id, size_t build_id_len) +{ + size_t name_offset, desc_offset; + GElf_Nhdr note_header; + + if (build_id_len <= 0) { + goto end; + } + + /* + * Discard the return value as it contains the size of the note section + * and we don't need it. + */ + (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, + &desc_offset); + + /* + * Compare the binary build id with the supplied build id. + */ + if (memcmp(build_id, static_cast(note_data->d_buf) + desc_offset, + build_id_len) == 0) { + return 1; + } +end: + return 0; +} + +/** + * Checks if the build id stored in `bin` (bin->build_id) is matching the build + * id of the ondisk file (bin->elf_file). + * + * @param bin bin_info instance + * @param build_id build id to compare ot the on disk file + * @param build_id_len length of the build id + * + * @returns 1 on if the build id of stored in `bin` matches + * the build id of the ondisk file. + * 0 on if they are different or an error occurred. + */ +static +int is_build_id_matching(struct bin_info *bin) +{ + int ret, is_build_id, is_matching = 0; + Elf_Scn *curr_section = NULL, *next_section = NULL; + GElf_Shdr curr_section_hdr; + + if (!bin->build_id) { + goto error; + } + + /* Set ELF file if it hasn't been accessed yet. */ + if (!bin->elf_file) { + ret = bin_info_set_elf_file(bin); + if (ret) { + /* Failed to set ELF file. */ + goto error; + } + } + + next_section = elf_nextscn(bin->elf_file, curr_section); + if (!next_section) { + goto error; + } + + while (next_section) { + Elf_Data *note_data = NULL; + + curr_section = next_section; + next_section = elf_nextscn(bin->elf_file, curr_section); + + if (!gelf_getshdr(curr_section, &curr_section_hdr)) { + goto error; + } + + if (curr_section_hdr.sh_type != SHT_NOTE) { + continue; + } + + /* + * elf_getdata() translates the data to native byte order. + */ + note_data = elf_getdata(curr_section, NULL); + if (!note_data) { + goto error; + } + + /* Check if the note is of the build-id type. */ + is_build_id = is_build_id_note_section(note_data); + if (!is_build_id) { + continue; + } + + /* + * Compare the build id of the on-disk file and + * the build id recorded in the trace. + */ + is_matching = is_build_id_note_section_matching( + note_data, bin->build_id, bin->build_id_len); + if (!is_matching) { + break; + } + } +error: + return is_matching; +} + +int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, + size_t build_id_len) +{ + if (!bin || !build_id) { + goto error; + } + + /* Free any previously set build id. */ + g_free(bin->build_id); + + /* Set the build id. */ + bin->build_id = g_new0(uint8_t, build_id_len); + if (!bin->build_id) { + goto error; + } + + memcpy(bin->build_id, build_id, build_id_len); + bin->build_id_len = build_id_len; + + /* + * Check if the file found on the file system has the same build id + * that what was recorded in the trace. + */ + bin->file_build_id_matches = is_build_id_matching(bin); + if (!bin->file_build_id_matches) { + BT_COMP_LOGI_STR("Supplied Build ID does not match Build ID of the " + "binary or library found on the file system."); + goto error; + } + + /* + * Reset the is_elf_only flag in case it had been set + * previously, because we might find separate debug info using + * the new build id information. + */ + bin->is_elf_only = false; + + return 0; + +error: + return -1; +} + +int bin_info_set_debug_link(struct bin_info *bin, const char *filename, + uint32_t crc) +{ + if (!bin || !filename) { + goto error; + } + + bin->dbg_link_filename = g_strdup(filename); + if (!bin->dbg_link_filename) { + goto error; + } + + bin->dbg_link_crc = crc; + + /* + * Reset the is_elf_only flag in case it had been set + * previously, because we might find separate debug info using + * the new build id information. + */ + bin->is_elf_only = false; + + return 0; + +error: + + return -1; +} + +/** + * Tries to read DWARF info from the location given by path, and + * attach it to the given bin_info instance if it exists. + * + * @param bin bin_info instance for which to set DWARF info + * @param path Presumed location of the DWARF info + * @returns 0 on success, negative value on failure + */ +static +int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path) +{ + int ret = 0; + struct bt_fd_cache_handle *dwarf_handle = NULL; + struct bt_dwarf_cu *cu = NULL; + Dwarf *dwarf_info = NULL; + + if (!bin || !path) { + goto error; + } + + dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path); + if (!dwarf_handle) { + goto error; + } + + dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle), + DWARF_C_READ); + if (!dwarf_info) { + goto error; + } + + /* + * Check if the dwarf info has any CU. If not, the + * executable's object file contains no DWARF info. + */ + cu = bt_dwarf_cu_create(dwarf_info); + if (!cu) { + goto error; + } + + ret = bt_dwarf_cu_next(cu); + if (ret) { + goto error; + } + + bin->dwarf_handle = dwarf_handle; + bin->dwarf_path = g_strdup(path); + if (!bin->dwarf_path) { + goto error; + } + bin->dwarf_info = dwarf_info; + free(cu); + + return 0; + +error: + if (bin) { + bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle); + } + dwarf_end(dwarf_info); + g_free(dwarf_info); + free(cu); + + return -1; +} + +/** + * Try to set the dwarf_info for a given bin_info instance via the + * build ID method. + * + * @param bin bin_info instance for which to retrieve the + * DWARF info via build ID + * @returns 0 on success (i.e. dwarf_info set), -1 on failure + */ +static +int bin_info_set_dwarf_info_build_id(struct bin_info *bin) +{ + int i = 0, ret = 0; + char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL; + const char *dbg_dir = NULL; + size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len; + + if (!bin || !bin->build_id) { + goto error; + } + + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; + + /* + * The prefix dir is the first byte of the build id, represented in + * lowercase hex as two characters per byte, +1 for '\0'. + */ + build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1); + if (!build_id_prefix_dir) { + goto error; + } + g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]); + + /* + * The build id file is the remaining bytes of the build id, + * represented in lowercase hex, as two characters per byte. + */ + build_id_char_len = (2 * (bin->build_id_len - 1)); + + /* To which the build id suffix is added, +1 for '\0'. */ + build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1; + + /* + * The resulting filename string is the concatenation of the + * hex build id and the suffix. + */ + build_id_file_len = build_id_char_len + build_id_suffix_char_len; + build_id_file = g_new0(gchar, build_id_file_len); + if (!build_id_file) { + goto error; + } + + /* + * For each byte, starting at offset 1, append two characters + * in lowercase hex. + */ + for (i = 1; i < bin->build_id_len; ++i) { + int path_idx = 2 * (i - 1); + + g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); + } + /* Append the suffix to the generated string, including the '\0'. */ + g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len, + BUILD_ID_SUFFIX); + + path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL); + if (!path) { + goto error; + } + + ret = bin_info_set_dwarf_info_from_path(bin, path); + if (ret) { + goto error; + } + + goto end; + +error: + ret = -1; +end: + g_free(build_id_prefix_dir); + g_free(build_id_file); + g_free(path); + + return ret; +} + +/** + * Tests whether the file located at path exists and has the expected + * checksum. + * + * This predicate is used when looking up separate debug info via the + * GNU debuglink method. The expected crc can be found .gnu_debuglink + * section in the original ELF file, along with the filename for the + * file containing the debug info. + * + * @param path Full path at which to look for the debug file + * @param crc Expected checksum for the debug file + * @returns 1 if the file exists and has the correct checksum, + * 0 otherwise + */ +static +int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc) +{ + int ret = 0; + struct bt_fd_cache_handle *debug_handle = NULL; + uint32_t _crc = 0; + + if (!path) { + goto end; + } + + debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path); + if (!debug_handle) { + goto end; + } + + ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc); + if (ret) { + ret = 0; + goto end; + } + + ret = (crc == _crc); + +end: + bt_fd_cache_put_handle(bin->fd_cache, debug_handle); + return ret; +} + +/** + * Try to set the dwarf_info for a given bin_info instance via the + * debug-link method. + * + * @param bin bin_info instance for which to retrieve the + * DWARF info via debug link + * @returns 0 on success (i.e. dwarf_info set), -1 on failure + */ +static +int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) +{ + int ret = 0; + const gchar *dbg_dir = NULL; + gchar *bin_dir = NULL, *path = NULL; + + if (!bin || !bin->dbg_link_filename) { + goto error; + } + + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; + bin_dir = g_path_get_dirname(bin->elf_path); + + /* First look in the executable's dir */ + path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL); + + if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { + goto found; + } + + /* If not found, look in .debug subdir */ + g_free(path); + path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); + + if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { + goto found; + } + + /* Lastly, look under the global debug directory */ + g_free(path); + + path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); + if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { + goto found; + } + +error: + ret = -1; +end: + g_free(bin_dir); + g_free(path); + + return ret; + +found: + ret = bin_info_set_dwarf_info_from_path(bin, path); + if (ret) { + goto error; + } + + goto end; +} + +/** + * Initialize the DWARF info for a given executable. + * + * @param bin bin_info instance + * @returns 0 on success, negative value on failure + */ +static +int bin_info_set_dwarf_info(struct bin_info *bin) +{ + int ret = 0; + + if (!bin) { + ret = -1; + goto end; + } + + /* First try to set the DWARF info from the ELF file */ + ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path); + if (!ret) { + goto end; + } + + /* + * If that fails, try to find separate debug info via build ID + * and debug link. + */ + ret = bin_info_set_dwarf_info_build_id(bin); + if (!ret) { + goto end; + } + + ret = bin_info_set_dwarf_info_debug_link(bin); + if (!ret) { + goto end; + } + +end: + return ret; +} + +void source_location_destroy(struct source_location *src_loc) +{ + if (!src_loc) { + return; + } + + free(src_loc->filename); + g_free(src_loc); +} + +/** + * Append a string representation of an address offset to an existing + * string. + * + * On success, the out parameter `result` will contain the base string + * followed by the offset string of the form "+0x1234". On failure, + * `result` remains unchanged. + * + * @param base_str The string to which to append an offset string + * @param low_addr The lower virtual memory address, the base from + * which the offset is computed + * @param high_addr The higher virtual memory address + * @param result Out parameter, the base string followed by the + * offset string + * @returns 0 on success, -1 on failure + */ +static +int bin_info_append_offset_str(const char *base_str, uint64_t low_addr, + uint64_t high_addr, char **result) +{ + uint64_t offset; + char *_result = NULL; + + if (!base_str || !result) { + goto error; + } + + offset = high_addr - low_addr; + + _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset); + if (!_result) { + goto error; + } + *result = _result; + + return 0; + +error: + free(_result); + return -1; +} + +/** + * Try to find the symbol closest to an address within a given ELF + * section. + * + * Only function symbols are taken into account. The symbol's address + * must precede `addr`. A symbol with a closer address might exist + * after `addr` but is irrelevant because it cannot encompass `addr`. + * + * On success, if found, the out parameters `sym` and `shdr` are + * set. On failure or if none are found, they remain unchanged. + * + * @param scn ELF section in which to look for the address + * @param addr Virtual memory address for which to find the + * nearest function symbol + * @param sym Out parameter, the nearest function symbol + * @param shdr Out parameter, the section header for scn + * @returns 0 on success, -1 on failure + */ +static +int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr, + GElf_Sym **sym, GElf_Shdr **shdr) +{ + int i; + size_t symbol_count; + Elf_Data *data = NULL; + GElf_Shdr *_shdr = NULL; + GElf_Sym *nearest_sym = NULL; + + if (!scn || !sym || !shdr) { + goto error; + } + + _shdr = g_new0(GElf_Shdr, 1); + if (!_shdr) { + goto error; + } + + _shdr = gelf_getshdr(scn, _shdr); + if (!_shdr) { + goto error; + } + + if (_shdr->sh_type != SHT_SYMTAB) { + /* + * We are only interested in symbol table (symtab) + * sections, skip this one. + */ + goto end; + } + + data = elf_getdata(scn, NULL); + if (!data) { + goto error; + } + + symbol_count = _shdr->sh_size / _shdr->sh_entsize; + + for (i = 0; i < symbol_count; ++i) { + GElf_Sym *cur_sym = NULL; + + cur_sym = g_new0(GElf_Sym, 1); + if (!cur_sym) { + goto error; + } + cur_sym = gelf_getsym(data, i, cur_sym); + if (!cur_sym) { + goto error; + } + if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) { + /* We're only interested in the functions. */ + g_free(cur_sym); + continue; + } + + if (cur_sym->st_value <= addr && + (!nearest_sym || + cur_sym->st_value > nearest_sym->st_value)) { + g_free(nearest_sym); + nearest_sym = cur_sym; + } else { + g_free(cur_sym); + } + } + +end: + if (nearest_sym) { + *sym = nearest_sym; + *shdr = _shdr; + } else { + g_free(_shdr); + } + + return 0; + +error: + g_free(nearest_sym); + g_free(_shdr); + return -1; +} + +/** + * Get the name of the function containing a given address within an + * executable using ELF symbols. + * + * The function name is in fact the name of the nearest ELF symbol, + * followed by the offset in bytes between the address and the symbol + * (in hex), separated by a '+' character. + * + * If found, the out parameter `func_name` is set on success. On failure, + * it remains unchanged. + * + * @param bin bin_info instance for the executable containing + * the address + * @param addr Virtual memory address for which to find the + * function name + * @param func_name Out parameter, the function name + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr, + char **func_name) +{ + /* + * TODO (possible optimisation): if an ELF has no symtab + * section, it has been stripped. Therefore, it would be wise + * to store a flag indicating the stripped status after the + * first iteration to prevent subsequent ones. + */ + int ret = 0; + Elf_Scn *scn = NULL; + GElf_Sym *sym = NULL; + GElf_Shdr *shdr = NULL; + char *sym_name = NULL; + + /* Set ELF file if it hasn't been accessed yet. */ + if (!bin->elf_file) { + ret = bin_info_set_elf_file(bin); + if (ret) { + /* Failed to set ELF file. */ + goto error; + } + } + + scn = elf_nextscn(bin->elf_file, scn); + if (!scn) { + goto error; + } + + while (scn && !sym) { + ret = bin_info_get_nearest_symbol_from_section( + scn, addr, &sym, &shdr); + if (ret) { + goto error; + } + + scn = elf_nextscn(bin->elf_file, scn); + } + + if (sym) { + sym_name = elf_strptr(bin->elf_file, shdr->sh_link, + sym->st_name); + if (!sym_name) { + goto error; + } + + ret = bin_info_append_offset_str(sym_name, sym->st_value, addr, + func_name); + if (ret) { + goto error; + } + } + + g_free(shdr); + g_free(sym); + return 0; + +error: + g_free(shdr); + g_free(sym); + return ret; +} + +/** + * Get the name of the function containing a given address within a + * given compile unit (CU). + * + * If found, the out parameter `func_name` is set on success. On + * failure, it remains unchanged. + * + * @param cu bt_dwarf_cu instance which may contain the address + * @param addr Virtual memory address for which to find the + * function name + * @param func_name Out parameter, the function name + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr, + char **func_name) +{ + int ret = 0; + bool found = false; + struct bt_dwarf_die *die = NULL; + + if (!cu || !func_name) { + goto error; + } + + die = bt_dwarf_die_create(cu); + if (!die) { + goto error; + } + + while (bt_dwarf_die_next(die) == 0) { + int tag; + + ret = bt_dwarf_die_get_tag(die, &tag); + if (ret) { + goto error; + } + + if (tag == DW_TAG_subprogram) { + ret = bt_dwarf_die_contains_addr(die, addr, &found); + if (ret) { + goto error; + } + + if (found) { + break; + } + } + } + + if (found) { + uint64_t low_addr = 0; + char *die_name = NULL; + + ret = bt_dwarf_die_get_name(die, &die_name); + if (ret) { + goto error; + } + + ret = dwarf_lowpc(die->dwarf_die, &low_addr); + if (ret) { + free(die_name); + goto error; + } + + ret = bin_info_append_offset_str(die_name, low_addr, addr, + func_name); + free(die_name); + if (ret) { + goto error; + } + } + + bt_dwarf_die_destroy(die); + return 0; + +error: + bt_dwarf_die_destroy(die); + return -1; +} + +/** + * Get the name of the function containing a given address within an + * executable using DWARF debug info. + * + * If found, the out parameter `func_name` is set on success. On + * failure, it remains unchanged. + * + * @param bin bin_info instance for the executable containing + * the address + * @param addr Virtual memory address for which to find the + * function name + * @param func_name Out parameter, the function name + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr, + char **func_name) +{ + int ret = 0; + char *_func_name = NULL; + struct bt_dwarf_cu *cu = NULL; + + if (!bin || !func_name) { + goto error; + } + + cu = bt_dwarf_cu_create(bin->dwarf_info); + if (!cu) { + goto error; + } + + while (bt_dwarf_cu_next(cu) == 0) { + ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name); + if (ret) { + goto error; + } + + if (_func_name) { + break; + } + } + + if (_func_name) { + *func_name = _func_name; + } else { + goto error; + } + + bt_dwarf_cu_destroy(cu); + return 0; + +error: + bt_dwarf_cu_destroy(cu); + return -1; +} + +int bin_info_lookup_function_name(struct bin_info *bin, + uint64_t addr, char **func_name) +{ + int ret = 0; + char *_func_name = NULL; + + if (!bin || !func_name) { + goto error; + } + + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + + /* Set DWARF info if it hasn't been accessed yet. */ + if (!bin->dwarf_info && !bin->is_elf_only) { + ret = bin_info_set_dwarf_info(bin); + if (ret) { + BT_COMP_LOGI_STR("Failed to set bin dwarf info, falling " + "back to ELF lookup."); + /* Failed to set DWARF info, fallback to ELF. */ + bin->is_elf_only = true; + } + } + + if (!bin_info_has_address(bin, addr)) { + goto error; + } + + /* + * Addresses in ELF and DWARF are relative to base address for + * PIC, so make the address argument relative too if needed. + */ + if (bin->is_pic) { + addr -= bin->low_addr; + } + + if (bin->is_elf_only) { + ret = bin_info_lookup_elf_function_name(bin, addr, + &_func_name); + if (ret) { + BT_COMP_LOGI("Failed to lookup function name (ELF): " + "ret=%d", ret); + } + } else { + ret = bin_info_lookup_dwarf_function_name(bin, addr, + &_func_name); + if (ret) { + BT_COMP_LOGI("Failed to lookup function name (DWARF): " + "ret=%d", ret); + } + } + + *func_name = _func_name; + return 0; + +error: + return -1; +} + +int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc) +{ + gchar *_bin_loc = NULL; + + if (!bin || !bin_loc) { + goto error; + } + + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + + if (bin->is_pic) { + addr -= bin->low_addr; + _bin_loc = g_strdup_printf("+%#0" PRIx64, addr); + } else { + _bin_loc = g_strdup_printf("@%#0" PRIx64, addr); + } + + if (!_bin_loc) { + goto error; + } + + *bin_loc = _bin_loc; + return 0; + +error: + return -1; +} + +/** + * Predicate used to determine whether the children of a given DIE + * contain a specific address. + * + * More specifically, the parameter `die` is expected to be a + * subprogram (function) DIE, and this predicate tells whether any + * subroutines are inlined within this function and would contain + * `addr`. + * + * On success, the out parameter `contains` is set with the boolean + * value indicating whether the DIE's range covers `addr`. On failure, + * it remains unchanged. + * + * Do note that this function advances the position of `die`. If the + * address is found within one of its children, `die` will be pointing + * to that child upon returning from the function, allowing to extract + * the information deemed necessary. + * + * @param die The parent DIE in whose children the address will be + * looked for + * @param addr The address for which to look for in the DIEs + * @param contains Out parameter, true if addr is contained, + * false if not + * @returns Returns 0 on success, -1 on failure + */ +static +int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains) +{ + int ret = 0; + bool _contains = false; + + if (!die) { + goto error; + } + + ret = bt_dwarf_die_child(die); + if (ret) { + goto error; + } + + do { + ret = bt_dwarf_die_contains_addr(die, addr, &_contains); + if (ret) { + goto error; + } + + if (_contains) { + /* + * The address is within the range of the current DIE + * or its children. + */ + int tag; + + ret = bt_dwarf_die_get_tag(die, &tag); + if (ret) { + goto error; + } + + if (tag == DW_TAG_inlined_subroutine) { + /* Found the tracepoint. */ + goto end; + } + + if (bt_dwarf_die_has_children(die)) { + /* + * Look for the address in the children DIEs. + */ + ret = bt_dwarf_die_child(die); + if (ret) { + goto error; + } + } + } + } while (bt_dwarf_die_next(die) == 0); + +end: + *contains = _contains; + return 0; + +error: + return -1; +} + +/** + * Lookup the source location for a given address within a CU, making + * the assumption that it is contained within an inline routine in a + * function. + * + * @param cu bt_dwarf_cu instance in which to look for the address + * @param addr The address for which to look for + * @param src_loc Out parameter, the source location (filename and + * line number) for the address + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr, + struct source_location **src_loc) +{ + int ret = 0; + bool found = false; + struct bt_dwarf_die *die = NULL; + struct source_location *_src_loc = NULL; + + if (!cu || !src_loc) { + goto error; + } + + die = bt_dwarf_die_create(cu); + if (!die) { + goto error; + } + + while (bt_dwarf_die_next(die) == 0) { + int tag; + + ret = bt_dwarf_die_get_tag(die, &tag); + if (ret) { + goto error; + } + + if (tag == DW_TAG_subprogram) { + bool contains = false; + + ret = bt_dwarf_die_contains_addr(die, addr, &contains); + if (ret) { + goto error; + } + + if (contains) { + /* + * Try to find an inlined subroutine + * child of this DIE containing addr. + */ + ret = bin_info_child_die_has_address(die, addr, + &found); + if(ret) { + goto error; + } + + goto end; + } + } + } + +end: + if (found) { + char *filename = NULL; + uint64_t line_no; + + _src_loc = g_new0(struct source_location, 1); + if (!_src_loc) { + goto error; + } + + ret = bt_dwarf_die_get_call_file(die, &filename); + if (ret) { + goto error; + } + ret = bt_dwarf_die_get_call_line(die, &line_no); + if (ret) { + free(filename); + goto error; + } + + _src_loc->filename = filename; + _src_loc->line_no = line_no; + *src_loc = _src_loc; + } + + bt_dwarf_die_destroy(die); + return 0; + +error: + source_location_destroy(_src_loc); + bt_dwarf_die_destroy(die); + return -1; +} + +/** + * Lookup the source location for a given address within a CU, + * assuming that it is contained within an inlined function. + * + * A source location can be found regardless of inlining status for + * this method, but in the case of an inlined function, the returned + * source location will point not to the callsite but rather to the + * definition site of the inline function. + * + * @param cu bt_dwarf_cu instance in which to look for the address + * @param addr The address for which to look for + * @param src_loc Out parameter, the source location (filename and + * line number) for the address. Set only if the address + * is found and resolved successfully + * + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, + struct source_location **src_loc) +{ + struct source_location *_src_loc = NULL; + struct bt_dwarf_die *die = NULL; + const char *filename = NULL; + Dwarf_Line *line = NULL; + Dwarf_Addr line_addr; + int ret = 0, line_no; + + if (!cu || !src_loc) { + goto error; + } + + die = bt_dwarf_die_create(cu); + if (!die) { + goto error; + } + + line = dwarf_getsrc_die(die->dwarf_die, addr); + if (!line) { + /* This is not an error. The caller needs to keep looking. */ + goto end; + } + + ret = dwarf_lineaddr(line, &line_addr); + if (ret) { + goto error; + } + + filename = dwarf_linesrc(line, NULL, NULL); + if (!filename) { + goto error; + } + + if (addr == line_addr) { + _src_loc = g_new0(struct source_location, 1); + if (!_src_loc) { + goto error; + } + + ret = dwarf_lineno(line, &line_no); + if (ret) { + goto error; + } + + _src_loc->line_no = line_no; + _src_loc->filename = g_strdup(filename); + } + + if (_src_loc) { + *src_loc = _src_loc; + } + + goto end; + +error: + source_location_destroy(_src_loc); + ret = -1; +end: + bt_dwarf_die_destroy(die); + return ret; +} + +/** + * Get the source location (file name and line number) for a given + * address within a compile unit (CU). + * + * On success, the out parameter `src_loc` is set if found. On + * failure, it remains unchanged. + * + * @param cu bt_dwarf_cu instance for the compile unit which + * may contain the address + * @param addr Virtual memory address for which to find the + * source location + * @param src_loc Out parameter, the source location + * @returns 0 on success, -1 on failure + */ +static +int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr, + struct source_location **src_loc) +{ + int ret = 0; + struct source_location *_src_loc = NULL; + + if (!cu || !src_loc) { + goto error; + } + + ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc); + if (ret) { + goto error; + } + + if (_src_loc) { + goto end; + } + + ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc); + if (ret) { + goto error; + } + + if (_src_loc) { + goto end; + } + +end: + if (_src_loc) { + *src_loc = _src_loc; + } + + return 0; + +error: + source_location_destroy(_src_loc); + return -1; +} + +int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr, + struct source_location **src_loc) +{ + struct bt_dwarf_cu *cu = NULL; + struct source_location *_src_loc = NULL; + + if (!bin || !src_loc) { + goto error; + } + + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + + /* Set DWARF info if it hasn't been accessed yet. */ + if (!bin->dwarf_info && !bin->is_elf_only) { + if (bin_info_set_dwarf_info(bin)) { + /* Failed to set DWARF info. */ + bin->is_elf_only = true; + } + } + + if (bin->is_elf_only) { + /* We cannot lookup source location without DWARF info. */ + goto error; + } + + if (!bin_info_has_address(bin, addr)) { + goto error; + } + + /* + * Addresses in ELF and DWARF are relative to base address for + * PIC, so make the address argument relative too if needed. + */ + if (bin->is_pic) { + addr -= bin->low_addr; + } + + cu = bt_dwarf_cu_create(bin->dwarf_info); + if (!cu) { + goto error; + } + + while (bt_dwarf_cu_next(cu) == 0) { + int ret; + + ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc); + if (ret) { + goto error; + } + + if (_src_loc) { + break; + } + } + + bt_dwarf_cu_destroy(cu); + if (_src_loc) { + *src_loc = _src_loc; + } + + return 0; + +error: + source_location_destroy(_src_loc); + bt_dwarf_cu_destroy(cu); + return -1; +} diff --git a/src/plugins/lttng-utils/debug-info/bin-info.h b/src/plugins/lttng-utils/debug-info/bin-info.h deleted file mode 100644 index 2a641691..00000000 --- a/src/plugins/lttng-utils/debug-info/bin-info.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2015 Antoine Busque - * - * Babeltrace - Executable and Shared Object Debug Info Reader - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_H - -#include -#include -#include -#include -#include -#include "common/macros.h" -#include "fd-cache/fd-cache.h" - -#define DEFAULT_DEBUG_DIR "/usr/lib/debug" -#define DEBUG_SUBDIR ".debug" -#define BUILD_ID_SUBDIR ".build-id" -#define BUILD_ID_SUFFIX ".debug" -#define BUILD_ID_PREFIX_DIR_LEN 2 - -struct bin_info { - bt_logging_level log_level; - - /* Used for logging; can be `NULL` */ - bt_self_component *self_comp; - - /* Base virtual memory address. */ - uint64_t low_addr; - /* Upper bound of exec address space. */ - uint64_t high_addr; - /* Size of exec address space. */ - uint64_t memsz; - /* Paths to ELF and DWARF files. */ - gchar *elf_path; - gchar *dwarf_path; - /* libelf and libdw objects representing the files. */ - Elf *elf_file; - Dwarf *dwarf_info; - /* Optional build ID info. */ - uint8_t *build_id; - size_t build_id_len; - - /* Optional debug link info. */ - gchar *dbg_link_filename; - uint32_t dbg_link_crc; - /* fd cache handles to ELF and DWARF files. */ - struct bt_fd_cache_handle *elf_handle; - struct bt_fd_cache_handle *dwarf_handle; - /* Configuration. */ - gchar *debug_info_dir; - /* Denotes whether the executable is position independent code. */ - bool is_pic:1; - /* Denotes whether the build id in the trace matches to one on disk. */ - bool file_build_id_matches:1; - /* - * Denotes whether the executable only has ELF symbols and no - * DWARF info. - */ - bool is_elf_only:1; - /* Weak ref. Owned by the iterator. */ - struct bt_fd_cache *fd_cache; -}; - -struct source_location { - uint64_t line_no; - gchar *filename; -}; - -/** - * Initializes the bin_info framework. Call this before calling - * anything else. - * - * @returns 0 on success, -1 on failure - */ -int bin_info_init(bt_logging_level log_level, - bt_self_component *self_comp); - -/** - * Instantiate a structure representing an ELF executable, possibly - * with DWARF info, located at the given path. - * - * @param path Path to the ELF file - * @param low_addr Base address of the executable - * @param memsz In-memory size of the executable - * @param is_pic Whether the executable is position independent - * code (PIC) - * @param debug_info_dir Directory containing debug info or NULL. - * @param target_prefix Path to the root file system of the target - * or NULL. - * @returns Pointer to the new bin_info on success, - * NULL on failure. - */ -struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path, - uint64_t low_addr, uint64_t memsz, bool is_pic, - const char *debug_info_dir, const char *target_prefix, - bt_logging_level log_level, bt_self_component *self_comp); - -/** - * Destroy the given bin_info instance - * - * @param bin bin_info instance to destroy - */ -void bin_info_destroy(struct bin_info *bin); - -/** - * Sets the build ID information for a given bin_info instance. - * - * @param bin The bin_info instance for which to set - * the build ID - * @param build_id Array of bytes containing the actual ID - * @param build_id_len Length in bytes of the build_id - * @returns 0 on success, -1 on failure - */ -int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, - size_t build_id_len); - -/** - * Sets the debug link information for a given bin_info instance. - * - * @param bin The bin_info instance for which to set - * the debug link - * @param filename Name of the separate debug info file - * @param crc Checksum for the debug info file - * @returns 0 on success, -1 on failure - */ -int bin_info_set_debug_link(struct bin_info *bin, const char *filename, - uint32_t crc); - -/** - * Returns whether or not the given bin info \p bin contains the - * address \p addr. - * - * @param bin bin_info instance - * @param addr Address to lookup - * @returns 1 if \p bin contains \p addr, 0 if it does not, - * -1 on failure - */ -static inline -int bin_info_has_address(struct bin_info *bin, uint64_t addr) -{ - if (!bin) { - return -1; - } - - return addr >= bin->low_addr && addr < bin->high_addr; -} - -/** - * Get the name of the function containing a given address within an - * executable. - * - * If no DWARF info is available, the function falls back to ELF - * symbols and the "function name" is in fact the name of the closest - * symbol, followed by the offset between the symbol and the address. - * - * On success, if found, the out parameter `func_name` is set. The ownership - * of `func_name` is passed to the caller. On failure, `func_name` remains - * unchanged. - * - * @param bin bin_info instance for the executable containing - * the address - * @param addr Virtual memory address for which to find the - * function name - * @param func_name Out parameter, the function name. - * @returns 0 on success, -1 on failure - */ -int bin_info_lookup_function_name(struct bin_info *bin, uint64_t addr, - char **func_name); - -/** - * Get the source location (file name and line number) for a given - * address within an executable. - * - * If no DWARF info is available, the source location cannot be found - * and the function will return unsuccessfully. - * - * On success, if found, the out parameter `src_loc` is set. The ownership - * of `src_loc` is passed to the caller. On failure, `src_loc` remains - * unchanged. - * - * @param bin bin_info instance for the executable containing - * the address - * @param addr Virtual memory address for which to find the - * source location - * @param src_loc Out parameter, the source location - * @returns 0 on success, -1 on failure - */ -int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr, - struct source_location **src_loc); -/** - * Get a string representing the location within the binary of a given - * address. - * - * In the case of a PIC binary, the location is relative (+0x1234). - * For a non-PIC binary, the location is absolute (@0x1234) - * - * On success, the out parameter `bin_loc` is set. The ownership is - * passed to the caller. On failure, `bin_loc` remains unchanged. - * - * @param bin bin_info instance for the executable containing - * the address - * @param addr Virtual memory address for which to find the - * binary location - * @param bin_loc Out parameter, the binary location - * @returns 0 on success, -1 on failure - */ -int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc); - -/** - * Destroy the given source_location instance - * - * @param src_loc source_location instance to destroy - */ -void source_location_destroy(struct source_location *src_loc); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_H */ diff --git a/src/plugins/lttng-utils/debug-info/bin-info.hpp b/src/plugins/lttng-utils/debug-info/bin-info.hpp new file mode 100644 index 00000000..ae489ae7 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/bin-info.hpp @@ -0,0 +1,223 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2015 Antoine Busque + * + * Babeltrace - Executable and Shared Object Debug Info Reader + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_HPP + +#include +#include +#include +#include +#include +#include "common/macros.h" +#include "fd-cache/fd-cache.hpp" + +#define DEFAULT_DEBUG_DIR "/usr/lib/debug" +#define DEBUG_SUBDIR ".debug" +#define BUILD_ID_SUBDIR ".build-id" +#define BUILD_ID_SUFFIX ".debug" +#define BUILD_ID_PREFIX_DIR_LEN 2 + +struct bin_info { + bt_logging_level log_level; + + /* Used for logging; can be `NULL` */ + bt_self_component *self_comp; + + /* Base virtual memory address. */ + uint64_t low_addr; + /* Upper bound of exec address space. */ + uint64_t high_addr; + /* Size of exec address space. */ + uint64_t memsz; + /* Paths to ELF and DWARF files. */ + gchar *elf_path; + gchar *dwarf_path; + /* libelf and libdw objects representing the files. */ + Elf *elf_file; + Dwarf *dwarf_info; + /* Optional build ID info. */ + uint8_t *build_id; + size_t build_id_len; + + /* Optional debug link info. */ + gchar *dbg_link_filename; + uint32_t dbg_link_crc; + /* fd cache handles to ELF and DWARF files. */ + struct bt_fd_cache_handle *elf_handle; + struct bt_fd_cache_handle *dwarf_handle; + /* Configuration. */ + gchar *debug_info_dir; + /* Denotes whether the executable is position independent code. */ + bool is_pic:1; + /* Denotes whether the build id in the trace matches to one on disk. */ + bool file_build_id_matches:1; + /* + * Denotes whether the executable only has ELF symbols and no + * DWARF info. + */ + bool is_elf_only:1; + /* Weak ref. Owned by the iterator. */ + struct bt_fd_cache *fd_cache; +}; + +struct source_location { + uint64_t line_no; + gchar *filename; +}; + +/** + * Initializes the bin_info framework. Call this before calling + * anything else. + * + * @returns 0 on success, -1 on failure + */ +int bin_info_init(bt_logging_level log_level, + bt_self_component *self_comp); + +/** + * Instantiate a structure representing an ELF executable, possibly + * with DWARF info, located at the given path. + * + * @param path Path to the ELF file + * @param low_addr Base address of the executable + * @param memsz In-memory size of the executable + * @param is_pic Whether the executable is position independent + * code (PIC) + * @param debug_info_dir Directory containing debug info or NULL. + * @param target_prefix Path to the root file system of the target + * or NULL. + * @returns Pointer to the new bin_info on success, + * NULL on failure. + */ +struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path, + uint64_t low_addr, uint64_t memsz, bool is_pic, + const char *debug_info_dir, const char *target_prefix, + bt_logging_level log_level, bt_self_component *self_comp); + +/** + * Destroy the given bin_info instance + * + * @param bin bin_info instance to destroy + */ +void bin_info_destroy(struct bin_info *bin); + +/** + * Sets the build ID information for a given bin_info instance. + * + * @param bin The bin_info instance for which to set + * the build ID + * @param build_id Array of bytes containing the actual ID + * @param build_id_len Length in bytes of the build_id + * @returns 0 on success, -1 on failure + */ +int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, + size_t build_id_len); + +/** + * Sets the debug link information for a given bin_info instance. + * + * @param bin The bin_info instance for which to set + * the debug link + * @param filename Name of the separate debug info file + * @param crc Checksum for the debug info file + * @returns 0 on success, -1 on failure + */ +int bin_info_set_debug_link(struct bin_info *bin, const char *filename, + uint32_t crc); + +/** + * Returns whether or not the given bin info \p bin contains the + * address \p addr. + * + * @param bin bin_info instance + * @param addr Address to lookup + * @returns 1 if \p bin contains \p addr, 0 if it does not, + * -1 on failure + */ +static inline +int bin_info_has_address(struct bin_info *bin, uint64_t addr) +{ + if (!bin) { + return -1; + } + + return addr >= bin->low_addr && addr < bin->high_addr; +} + +/** + * Get the name of the function containing a given address within an + * executable. + * + * If no DWARF info is available, the function falls back to ELF + * symbols and the "function name" is in fact the name of the closest + * symbol, followed by the offset between the symbol and the address. + * + * On success, if found, the out parameter `func_name` is set. The ownership + * of `func_name` is passed to the caller. On failure, `func_name` remains + * unchanged. + * + * @param bin bin_info instance for the executable containing + * the address + * @param addr Virtual memory address for which to find the + * function name + * @param func_name Out parameter, the function name. + * @returns 0 on success, -1 on failure + */ +int bin_info_lookup_function_name(struct bin_info *bin, uint64_t addr, + char **func_name); + +/** + * Get the source location (file name and line number) for a given + * address within an executable. + * + * If no DWARF info is available, the source location cannot be found + * and the function will return unsuccessfully. + * + * On success, if found, the out parameter `src_loc` is set. The ownership + * of `src_loc` is passed to the caller. On failure, `src_loc` remains + * unchanged. + * + * @param bin bin_info instance for the executable containing + * the address + * @param addr Virtual memory address for which to find the + * source location + * @param src_loc Out parameter, the source location + * @returns 0 on success, -1 on failure + */ +int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr, + struct source_location **src_loc); +/** + * Get a string representing the location within the binary of a given + * address. + * + * In the case of a PIC binary, the location is relative (+0x1234). + * For a non-PIC binary, the location is absolute (@0x1234) + * + * On success, the out parameter `bin_loc` is set. The ownership is + * passed to the caller. On failure, `bin_loc` remains unchanged. + * + * @param bin bin_info instance for the executable containing + * the address + * @param addr Virtual memory address for which to find the + * binary location + * @param bin_loc Out parameter, the binary location + * @returns 0 on success, -1 on failure + */ +int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc); + +/** + * Destroy the given source_location instance + * + * @param src_loc source_location instance to destroy + */ +void source_location_destroy(struct source_location *src_loc); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_BIN_INFO_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/crc32.h b/src/plugins/lttng-utils/debug-info/crc32.h index 5dedda43..c964f583 100644 --- a/src/plugins/lttng-utils/debug-info/crc32.h +++ b/src/plugins/lttng-utils/debug-info/crc32.h @@ -12,6 +12,10 @@ #include #include "common/macros.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * Compute a 32-bit cyclic redundancy checksum for a given file. * @@ -24,4 +28,8 @@ */ int crc32(int fd, uint32_t *crc); +#ifdef __cplusplus +} +#endif + #endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_CRC32_H */ diff --git a/src/plugins/lttng-utils/debug-info/debug-info.c b/src/plugins/lttng-utils/debug-info/debug-info.c deleted file mode 100644 index f8ef8182..00000000 --- a/src/plugins/lttng-utils/debug-info/debug-info.c +++ /dev/null @@ -1,2093 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015 Philippe Proulx - * Copyright (c) 2015 Antoine Busque - * Copyright (c) 2016 Jérémie Galarneau - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Debug Information State Tracker - */ - -#define BT_COMP_LOG_SELF_COMP self_comp -#define BT_LOG_OUTPUT_LEVEL log_level -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO" -#include "logging/comp-logging.h" - -#include - -#include - -#include "common/assert.h" -#include "common/common.h" -#include "fd-cache/fd-cache.h" - -#include "bin-info.h" -#include "debug-info.h" -#include "trace-ir-data-copy.h" -#include "trace-ir-mapping.h" -#include "trace-ir-metadata-copy.h" -#include "utils.h" -#include "plugins/common/param-validation/param-validation.h" - -#define DEFAULT_DEBUG_INFO_FIELD_NAME "debug_info" -#define LTTNG_UST_STATEDUMP_PREFIX "lttng_ust" - -struct debug_info_component { - bt_logging_level log_level; - bt_self_component *self_comp; - bt_self_component_filter *self_comp_filter; - gchar *arg_debug_dir; - gchar *arg_debug_info_field_name; - gchar *arg_target_prefix; - bt_bool arg_full_path; -}; - -struct debug_info_msg_iter { - bt_logging_level log_level; - struct debug_info_component *debug_info_component; - bt_self_message_iterator *input_iterator; - bt_self_component *self_comp; - bt_message_iterator *msg_iter; - - struct trace_ir_maps *ir_maps; - /* in_trace -> debug_info_mapping. */ - GHashTable *debug_info_map; - - struct bt_fd_cache fd_cache; -}; - -struct debug_info_source { - /* Strings are owned by debug_info_source. */ - gchar *func; - /* - * Store the line number as a string so that the allocation and - * conversion to string is only done once. - */ - gchar *line_no; - gchar *src_path; - /* short_src_path points inside src_path, no need to free. */ - const gchar *short_src_path; - gchar *bin_path; - /* short_bin_path points inside bin_path, no need to free. */ - const gchar *short_bin_path; - /* - * Location within the binary. Either absolute (@0x1234) or - * relative (+0x4321). - */ - gchar *bin_loc; -}; - -struct proc_debug_info_sources { - /* - * Hash table: base address (pointer to uint64_t) to bin info; owned by - * proc_debug_info_sources. - */ - GHashTable *baddr_to_bin_info; - - /* - * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *); - * owned by proc_debug_info_sources. - */ - GHashTable *ip_to_debug_info_src; -}; - -struct debug_info { - bt_logging_level log_level; - bt_self_component *self_comp; - struct debug_info_component *comp; - const bt_trace *input_trace; - bt_listener_id destruction_listener_id; - - /* - * Hash table of VPIDs (pointer to int64_t) to - * (struct proc_debug_info_sources*); owned by debug_info. - */ - GHashTable *vpid_to_proc_dbg_info_src; - GQuark q_statedump_bin_info; - GQuark q_statedump_debug_link; - GQuark q_statedump_build_id; - GQuark q_statedump_start; - GQuark q_dl_open; - GQuark q_lib_load; - GQuark q_lib_unload; - struct bt_fd_cache *fd_cache; /* Weak ref. Owned by the iterator. */ -}; - -static -int debug_info_init(struct debug_info *info) -{ - info->q_statedump_bin_info = g_quark_from_string( - "lttng_ust_statedump:bin_info"); - info->q_statedump_debug_link = g_quark_from_string( - "lttng_ust_statedump:debug_link"); - info->q_statedump_build_id = g_quark_from_string( - "lttng_ust_statedump:build_id"); - info->q_statedump_start = g_quark_from_string( - "lttng_ust_statedump:start"); - info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen"); - info->q_lib_load = g_quark_from_string("lttng_ust_lib:load"); - info->q_lib_unload = g_quark_from_string("lttng_ust_lib:unload"); - - return bin_info_init(info->log_level, info->self_comp); -} - -static -void debug_info_source_destroy(struct debug_info_source *debug_info_src) -{ - if (!debug_info_src) { - return; - } - - g_free(debug_info_src->func); - g_free(debug_info_src->line_no); - g_free(debug_info_src->src_path); - g_free(debug_info_src->bin_path); - g_free(debug_info_src->bin_loc); - g_free(debug_info_src); -} - -static -struct debug_info_source *debug_info_source_create_from_bin( - struct bin_info *bin, uint64_t ip, - bt_self_component *self_comp) -{ - int ret; - struct debug_info_source *debug_info_src = NULL; - struct source_location *src_loc = NULL; - bt_logging_level log_level; - - BT_ASSERT(bin); - - log_level = bin->log_level; - - debug_info_src = g_new0(struct debug_info_source, 1); - - if (!debug_info_src) { - goto end; - } - - /* Lookup function name */ - ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func); - if (ret) { - goto error; - } - - /* Can't retrieve src_loc from ELF, or could not find binary, skip. */ - if (!bin->is_elf_only || !debug_info_src->func) { - /* Lookup source location */ - ret = bin_info_lookup_source_location(bin, ip, &src_loc); - if (ret) { - BT_COMP_LOGI("Failed to lookup source location: ret=%d", ret); - } - } - - if (src_loc) { - debug_info_src->line_no = - g_strdup_printf("%"PRId64, src_loc->line_no); - if (!debug_info_src->line_no) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error occurred when setting `line_no` field."); - goto error; - } - - if (src_loc->filename) { - debug_info_src->src_path = g_strdup(src_loc->filename); - if (!debug_info_src->src_path) { - goto error; - } - - debug_info_src->short_src_path = get_filename_from_path( - debug_info_src->src_path); - } - source_location_destroy(src_loc); - } - - if (bin->elf_path) { - debug_info_src->bin_path = g_strdup(bin->elf_path); - if (!debug_info_src->bin_path) { - goto error; - } - - debug_info_src->short_bin_path = get_filename_from_path( - debug_info_src->bin_path); - - ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc)); - if (ret) { - goto error; - } - } - -end: - return debug_info_src; - -error: - debug_info_source_destroy(debug_info_src); - return NULL; -} - -static -void proc_debug_info_sources_destroy( - struct proc_debug_info_sources *proc_dbg_info_src) -{ - if (!proc_dbg_info_src) { - return; - } - - if (proc_dbg_info_src->baddr_to_bin_info) { - g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info); - } - - if (proc_dbg_info_src->ip_to_debug_info_src) { - g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src); - } - - g_free(proc_dbg_info_src); -} - -static -struct proc_debug_info_sources *proc_debug_info_sources_create(void) -{ - struct proc_debug_info_sources *proc_dbg_info_src = NULL; - - proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1); - if (!proc_dbg_info_src) { - goto end; - } - - proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full( - g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, - (GDestroyNotify) bin_info_destroy); - if (!proc_dbg_info_src->baddr_to_bin_info) { - goto error; - } - - proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full( - g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, - (GDestroyNotify) debug_info_source_destroy); - if (!proc_dbg_info_src->ip_to_debug_info_src) { - goto error; - } - -end: - return proc_dbg_info_src; - -error: - proc_debug_info_sources_destroy(proc_dbg_info_src); - return NULL; -} - -static -struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry( - GHashTable *ht, int64_t vpid) -{ - gpointer key = g_new0(int64_t, 1); - struct proc_debug_info_sources *proc_dbg_info_src = NULL; - - if (!key) { - goto end; - } - - *((int64_t *) key) = vpid; - - /* Exists? Return it */ - proc_dbg_info_src = g_hash_table_lookup(ht, key); - if (proc_dbg_info_src) { - goto end; - } - - /* Otherwise, create and return it */ - proc_dbg_info_src = proc_debug_info_sources_create(); - if (!proc_dbg_info_src) { - goto end; - } - - g_hash_table_insert(ht, key, proc_dbg_info_src); - /* Ownership passed to ht */ - key = NULL; -end: - g_free(key); - return proc_dbg_info_src; -} - -static inline -const bt_field *event_borrow_payload_field(const bt_event *event, - const char *field_name) -{ - const bt_field *event_payload, *field; - - event_payload = bt_event_borrow_payload_field_const(event); - BT_ASSERT_DBG(event_payload); - - field = bt_field_structure_borrow_member_field_by_name_const( - event_payload, field_name); - return field; -} - -static inline -const bt_field *event_borrow_common_context_field(const bt_event *event, - const char *field_name) -{ - const bt_field *event_common_ctx, *field = NULL; - - event_common_ctx = bt_event_borrow_common_context_field_const(event); - if (!event_common_ctx) { - goto end; - } - - field = bt_field_structure_borrow_member_field_by_name_const( - event_common_ctx, field_name); - -end: - return field; -} - -static inline -void event_get_common_context_signed_integer_field_value( - const bt_event *event, const char *field_name, int64_t *value) -{ - *value = bt_field_integer_signed_get_value( - event_borrow_common_context_field(event, field_name)); -} - -static inline -void event_get_payload_build_id_length(const bt_event *event, - const char *field_name, uint64_t *build_id_len) -{ - const bt_field *build_id_field; - const bt_field_class *build_id_field_class; - - build_id_field = event_borrow_payload_field(event, field_name); - build_id_field_class = bt_field_borrow_class_const(build_id_field); - - BT_ASSERT(bt_field_class_get_type(build_id_field_class) == - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD || - bt_field_class_get_type(build_id_field_class) == - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD); - BT_ASSERT(bt_field_class_get_type( - bt_field_class_array_borrow_element_field_class_const( - build_id_field_class)) == - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER); - - *build_id_len = bt_field_array_get_length(build_id_field); -} - -static inline -void event_get_payload_build_id_value(const bt_event *event, - const char *field_name, uint8_t *build_id) -{ - const bt_field *curr_field, *build_id_field; - const bt_field_class *build_id_field_class; - uint64_t i, build_id_len; - - build_id_field = event_borrow_payload_field(event, field_name); - build_id_field_class = bt_field_borrow_class_const(build_id_field); - - BT_ASSERT(bt_field_class_get_type(build_id_field_class) == - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD || - bt_field_class_get_type(build_id_field_class) == - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD); - BT_ASSERT(bt_field_class_get_type( - bt_field_class_array_borrow_element_field_class_const( - build_id_field_class)) == - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER); - - build_id_len = bt_field_array_get_length(build_id_field); - - for (i = 0; i < build_id_len; i++) { - curr_field = bt_field_array_borrow_element_field_by_index_const( - build_id_field, i); - - build_id[i] = bt_field_integer_unsigned_get_value(curr_field); - } -} - -static -void event_get_payload_unsigned_integer_field_value(const bt_event *event, - const char *field_name, uint64_t *value) -{ - *value = bt_field_integer_unsigned_get_value( - event_borrow_payload_field(event, field_name)); -} - -static -void event_get_payload_string_field_value(const bt_event *event, - const char *field_name, const char **value) -{ - *value = bt_field_string_get_value( - event_borrow_payload_field(event, field_name)); -} - -static inline -bool event_has_payload_field(const bt_event *event, - const char *field_name) -{ - return event_borrow_payload_field(event, field_name); -} - -static -struct debug_info_source *proc_debug_info_sources_get_entry( - struct debug_info *debug_info, - struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip) -{ - struct debug_info_source *debug_info_src = NULL; - gpointer key = g_new0(uint64_t, 1); - GHashTableIter iter; - gpointer baddr, value; - - if (!key) { - goto end; - } - - *((uint64_t *) key) = ip; - - /* Look in IP to debug infos hash table first. */ - debug_info_src = g_hash_table_lookup( - proc_dbg_info_src->ip_to_debug_info_src, key); - if (debug_info_src) { - goto end; - } - - /* Check in all bin_infos. */ - g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info); - - while (g_hash_table_iter_next(&iter, &baddr, &value)) - { - struct bin_info *bin = value; - - if (!bin_info_has_address(value, ip)) { - continue; - } - - /* - * Found; add it to cache. - * - * FIXME: this should be bounded in size (and implement - * a caching policy), and entries should be prunned when - * libraries are unmapped. - */ - debug_info_src = debug_info_source_create_from_bin(bin, ip, - debug_info->self_comp); - if (debug_info_src) { - g_hash_table_insert( - proc_dbg_info_src->ip_to_debug_info_src, key, - debug_info_src); - /* Ownership passed to ht. */ - key = NULL; - } - break; - } - -end: - free(key); - return debug_info_src; -} - -static -struct debug_info_source *debug_info_query(struct debug_info *debug_info, - int64_t vpid, uint64_t ip) -{ - struct debug_info_source *dbg_info_src = NULL; - struct proc_debug_info_sources *proc_dbg_info_src; - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - goto end; - } - - dbg_info_src = proc_debug_info_sources_get_entry(debug_info, - proc_dbg_info_src, ip); - -end: - return dbg_info_src; -} - -static -struct debug_info *debug_info_create(struct debug_info_component *comp, - const bt_trace *trace, struct bt_fd_cache *fdc) -{ - int ret; - struct debug_info *debug_info; - - BT_ASSERT(comp); - BT_ASSERT(trace); - BT_ASSERT(fdc); - - debug_info = g_new0(struct debug_info, 1); - if (!debug_info) { - goto end; - } - - debug_info->log_level = comp->log_level; - debug_info->self_comp = comp->self_comp; - debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full( - g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, - (GDestroyNotify) proc_debug_info_sources_destroy); - if (!debug_info->vpid_to_proc_dbg_info_src) { - goto error; - } - - debug_info->comp = comp; - ret = debug_info_init(debug_info); - if (ret) { - goto error; - } - - debug_info->input_trace = trace; - debug_info->fd_cache = fdc; - -end: - return debug_info; -error: - g_free(debug_info); - return NULL; -} - -static -void debug_info_destroy(struct debug_info *debug_info) -{ - bt_logging_level log_level; - bt_self_component *self_comp; - bt_trace_remove_listener_status remove_listener_status; - if (!debug_info) { - goto end; - } - - log_level = debug_info->log_level; - self_comp = debug_info->self_comp; - - if (debug_info->vpid_to_proc_dbg_info_src) { - g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src); - } - - remove_listener_status = bt_trace_remove_destruction_listener( - debug_info->input_trace, - debug_info->destruction_listener_id); - if (remove_listener_status != BT_TRACE_REMOVE_LISTENER_STATUS_OK) { - BT_COMP_LOGE("Trace destruction listener removal failed."); - bt_current_thread_clear_error(); - } - - g_free(debug_info); -end: - return; -} - -static -void handle_event_statedump_build_id(struct debug_info *debug_info, - const bt_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - uint64_t build_id_len, baddr; - uint8_t *build_id = NULL; - struct bin_info *bin; - int64_t vpid; - int ret = 0; - - event_get_common_context_signed_integer_field_value(event, - VPID_FIELD_NAME, &vpid); - event_get_payload_unsigned_integer_field_value(event, - BADDR_FIELD_NAME, &baddr); - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - goto end; - } - - bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, - (gpointer) &baddr); - if (!bin) { - /* - * The build_id event comes after the bin has been - * created. If it isn't found, just ignore this event. - */ - goto end; - } - - event_get_payload_build_id_length(event, BUILD_ID_FIELD_NAME, - &build_id_len); - - build_id = g_new0(uint8_t, build_id_len); - if (!build_id) { - goto end; - } - - event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME, build_id); - - ret = bin_info_set_build_id(bin, build_id, build_id_len); - if (ret) { - goto end; - } - - /* - * Reset the is_elf_only flag in case it had been set - * previously, because we might find separate debug info using - * the new build id information. - */ - bin->is_elf_only = false; - -end: - g_free(build_id); - return; -} - -static -void handle_event_statedump_debug_link(struct debug_info *debug_info, - const bt_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - struct bin_info *bin = NULL; - int64_t vpid; - uint64_t baddr; - const char *filename = NULL; - uint32_t crc32; - uint64_t crc_field_value; - - event_get_common_context_signed_integer_field_value(event, - VPID_FIELD_NAME, &vpid); - - event_get_payload_unsigned_integer_field_value(event, - BADDR_FIELD_NAME, &baddr); - - event_get_payload_unsigned_integer_field_value(event, - CRC32_FIELD_NAME, &crc_field_value); - - crc32 = (uint32_t) crc_field_value; - - event_get_payload_string_field_value(event, - FILENAME_FIELD_NAME, &filename); - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - goto end; - } - - bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, - (gpointer) &baddr); - if (!bin) { - /* - * The debug_link event comes after the bin has been - * created. If it isn't found, just ignore this event. - */ - goto end; - } - - bin_info_set_debug_link(bin, filename, crc32); - -end: - return; -} - -static -void handle_bin_info_event(struct debug_info *debug_info, - const bt_event *event, bool has_pic_field) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - struct bin_info *bin; - uint64_t baddr, memsz; - int64_t vpid; - const char *path; - gpointer key = NULL; - bool is_pic; - - event_get_payload_unsigned_integer_field_value(event, - MEMSZ_FIELD_NAME, &memsz); - if (memsz == 0) { - /* Ignore VDSO. */ - goto end; - } - - event_get_payload_unsigned_integer_field_value(event, - BADDR_FIELD_NAME, &baddr); - - /* - * This field is not produced by the dlopen event emitted before - * lttng-ust 2.9. - */ - if (!event_has_payload_field(event, PATH_FIELD_NAME)) { - goto end; - } - event_get_payload_string_field_value(event, PATH_FIELD_NAME, &path); - - if (has_pic_field) { - uint64_t is_pic_field_value; - - event_get_payload_unsigned_integer_field_value(event, - IS_PIC_FIELD_NAME, &is_pic_field_value); - is_pic = is_pic_field_value == 1; - } else { - /* - * dlopen has no is_pic field, because the shared - * object is always PIC. - */ - is_pic = true; - } - - event_get_common_context_signed_integer_field_value(event, - VPID_FIELD_NAME, &vpid); - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - goto end; - } - - key = g_new0(uint64_t, 1); - if (!key) { - goto end; - } - - *((uint64_t *) key) = baddr; - - bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, key); - if (bin) { - goto end; - } - - bin = bin_info_create(debug_info->fd_cache, path, baddr, memsz, is_pic, - debug_info->comp->arg_debug_dir, - debug_info->comp->arg_target_prefix, - debug_info->log_level, debug_info->self_comp); - if (!bin) { - goto end; - } - - g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, key, bin); - /* Ownership passed to ht. */ - key = NULL; - -end: - g_free(key); - return; -} - -static inline -void handle_event_statedump_bin_info(struct debug_info *debug_info, - const bt_event *event) -{ - handle_bin_info_event(debug_info, event, true); -} - -static inline -void handle_event_lib_load(struct debug_info *debug_info, - const bt_event *event) -{ - handle_bin_info_event(debug_info, event, false); -} - -static -void handle_event_lib_unload(struct debug_info *debug_info, - const bt_event *event) -{ - gboolean ret; - struct proc_debug_info_sources *proc_dbg_info_src; - uint64_t baddr; - int64_t vpid; - - event_get_payload_unsigned_integer_field_value(event, BADDR_FIELD_NAME, - &baddr); - - event_get_common_context_signed_integer_field_value(event, - VPID_FIELD_NAME, &vpid); - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - /* - * It's an unload event for a library for which no load event - * was previously received. - */ - goto end; - } - - ret = g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info, - (gpointer) &baddr); - BT_ASSERT(ret); -end: - return; -} - -static -void handle_event_statedump_start(struct debug_info *debug_info, - const bt_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - int64_t vpid; - - event_get_common_context_signed_integer_field_value( - event, VPID_FIELD_NAME, &vpid); - - proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( - debug_info->vpid_to_proc_dbg_info_src, vpid); - if (!proc_dbg_info_src) { - goto end; - } - - g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info); - g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src); - -end: - return; -} - -static -void trace_debug_info_remove_func(const bt_trace *in_trace, void *data) -{ - struct debug_info_msg_iter *debug_it = data; - if (debug_it->debug_info_map) { - gboolean ret; - ret = g_hash_table_remove(debug_it->debug_info_map, - (gpointer) in_trace); - BT_ASSERT(ret); - } -} - -static -void handle_event_statedump(struct debug_info_msg_iter *debug_it, - const bt_event *event) -{ - const bt_event_class *event_class; - const char *event_name; - GQuark q_event_name; - const bt_trace *trace; - struct debug_info *debug_info; - - BT_ASSERT(debug_it); - BT_ASSERT(event); - - event_class = bt_event_borrow_class_const(event); - - event_name = bt_event_class_get_name(event_class); - - trace = bt_stream_borrow_trace_const( - bt_event_borrow_stream_const(event)); - - debug_info = g_hash_table_lookup(debug_it->debug_info_map, trace); - if (!debug_info) { - bt_trace_add_listener_status add_listener_status; - - debug_info = debug_info_create(debug_it->debug_info_component, - trace, &debug_it->fd_cache); - g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace, - debug_info); - add_listener_status = bt_trace_add_destruction_listener( - trace, trace_debug_info_remove_func, debug_it, - &debug_info->destruction_listener_id); - BT_ASSERT(add_listener_status == BT_TRACE_ADD_LISTENER_STATUS_OK); - } - - q_event_name = g_quark_try_string(event_name); - - if (q_event_name == debug_info->q_statedump_bin_info) { - /* State dump */ - handle_event_statedump_bin_info(debug_info, event); - } else if (q_event_name == debug_info->q_dl_open || - q_event_name == debug_info->q_lib_load) { - /* - * dl_open and lib_load events are both checked for since - * only dl_open was produced as of lttng-ust 2.8. - * - * lib_load, which is produced from lttng-ust 2.9+, is a lot - * more reliable since it will be emitted when other functions - * of the dlopen family are called (e.g. dlmopen) and when - * library are transitively loaded. - */ - handle_event_lib_load(debug_info, event); - } else if (q_event_name == debug_info->q_statedump_start) { - /* Start state dump */ - handle_event_statedump_start(debug_info, event); - } else if (q_event_name == debug_info->q_statedump_debug_link) { - /* Debug link info */ - handle_event_statedump_debug_link(debug_info, event); - } else if (q_event_name == debug_info->q_statedump_build_id) { - /* Build ID info */ - handle_event_statedump_build_id(debug_info, event); - } else if (q_event_name == debug_info->q_lib_unload) { - handle_event_lib_unload(debug_info, event); - } - - return; -} - -static -void destroy_debug_info_comp(struct debug_info_component *debug_info) -{ - if (!debug_info) { - return; - } - - g_free(debug_info->arg_debug_dir); - g_free(debug_info->arg_debug_info_field_name); - g_free(debug_info->arg_target_prefix); - g_free(debug_info); -} - -static -void fill_debug_info_bin_field(struct debug_info_source *dbg_info_src, - bool full_path, bt_field *curr_field, - bt_logging_level log_level, bt_self_component *self_comp) -{ - bt_field_string_set_value_status set_status; - bt_field_string_append_status append_status; - - BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == - BT_FIELD_CLASS_TYPE_STRING); - - if (dbg_info_src) { - if (full_path) { - set_status = bt_field_string_set_value(curr_field, - dbg_info_src->bin_path); - } else { - set_status = bt_field_string_set_value(curr_field, - dbg_info_src->short_bin_path); - } - if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set path component of `bin` " - "curr_field field's value: str-fc-addr=%p", - curr_field); - bt_current_thread_clear_error(); - } - - append_status = bt_field_string_append(curr_field, - dbg_info_src->bin_loc); - if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { - BT_COMP_LOGE("Cannot set bin location component of `bin` " - "curr_field field's value: str-fc-addr=%p", - curr_field); - bt_current_thread_clear_error(); - } - } else { - set_status = bt_field_string_set_value(curr_field, ""); - if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `bin` curr_field field's value: " - "str-fc-addr=%p", curr_field); - bt_current_thread_clear_error(); - } - } -} - -static -void fill_debug_info_func_field(struct debug_info_source *dbg_info_src, - bt_field *curr_field, bt_logging_level log_level, - bt_self_component *self_comp) -{ - bt_field_string_set_value_status status; - - BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == - BT_FIELD_CLASS_TYPE_STRING); - if (dbg_info_src && dbg_info_src->func) { - status = bt_field_string_set_value(curr_field, - dbg_info_src->func); - } else { - status = bt_field_string_set_value(curr_field, ""); - } - if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `func` curr_field field's value: " - "str-fc-addr=%p", curr_field); - bt_current_thread_clear_error(); - } -} - -static -void fill_debug_info_src_field(struct debug_info_source *dbg_info_src, - bool full_path, bt_field *curr_field, - bt_logging_level log_level, - bt_self_component *self_comp) -{ - bt_field_string_set_value_status set_status; - bt_field_string_append_status append_status; - - BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == - BT_FIELD_CLASS_TYPE_STRING); - - if (dbg_info_src && dbg_info_src->src_path) { - if (full_path) { - set_status = bt_field_string_set_value(curr_field, - dbg_info_src->src_path); - } else { - set_status = bt_field_string_set_value(curr_field, - dbg_info_src->short_src_path); - } - if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set path component of `src` " - "curr_field field's value: str-fc-addr=%p", - curr_field); - bt_current_thread_clear_error(); - } - - append_status = bt_field_string_append(curr_field, ":"); - if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { - BT_COMP_LOGE("Cannot set colon component of `src` " - "curr_field field's value: str-fc-addr=%p", - curr_field); - bt_current_thread_clear_error(); - } - - append_status = bt_field_string_append(curr_field, - dbg_info_src->line_no); - if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { - BT_COMP_LOGE("Cannot set line number component of `src` " - "curr_field field's value: str-fc-addr=%p", - curr_field); - bt_current_thread_clear_error(); - } - } else { - set_status = bt_field_string_set_value(curr_field, ""); - if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `src` curr_field field's value: " - "str-fc-addr=%p", curr_field); - bt_current_thread_clear_error(); - } - } -} - -static -void fill_debug_info_field_empty(bt_field *debug_info_field, - bt_logging_level log_level, bt_self_component *self_comp) -{ - bt_field_string_set_value_status status; - bt_field *bin_field, *func_field, *src_field; - - BT_ASSERT_DBG(bt_field_get_class_type(debug_info_field) == - BT_FIELD_CLASS_TYPE_STRUCTURE); - - bin_field = bt_field_structure_borrow_member_field_by_name( - debug_info_field, "bin"); - func_field = bt_field_structure_borrow_member_field_by_name( - debug_info_field, "func"); - src_field = bt_field_structure_borrow_member_field_by_name( - debug_info_field, "src"); - - BT_ASSERT_DBG(bt_field_get_class_type(bin_field) == - BT_FIELD_CLASS_TYPE_STRING); - BT_ASSERT_DBG(bt_field_get_class_type(func_field) == - BT_FIELD_CLASS_TYPE_STRING); - BT_ASSERT_DBG(bt_field_get_class_type(src_field) == - BT_FIELD_CLASS_TYPE_STRING); - - status = bt_field_string_set_value(bin_field, ""); - if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `bin` field's value: " - "str-fc-addr=%p", bin_field); - bt_current_thread_clear_error(); - } - - status = bt_field_string_set_value(func_field, ""); - if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `func` field's value: " - "str-fc-addr=%p", func_field); - bt_current_thread_clear_error(); - } - - status = bt_field_string_set_value(src_field, ""); - if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE("Cannot set `src` field's value: " - "str-fc-addr=%p", src_field); - bt_current_thread_clear_error(); - } -} -static -void fill_debug_info_field(struct debug_info *debug_info, int64_t vpid, - uint64_t ip, bt_field *debug_info_field) -{ - struct debug_info_source *dbg_info_src; - const bt_field_class *debug_info_fc; - - BT_ASSERT_DBG(bt_field_get_class_type(debug_info_field) == - BT_FIELD_CLASS_TYPE_STRUCTURE); - - debug_info_fc = bt_field_borrow_class_const(debug_info_field); - - BT_ASSERT_DBG(bt_field_class_structure_get_member_count( - debug_info_fc) == 3); - - dbg_info_src = debug_info_query(debug_info, vpid, ip); - - fill_debug_info_bin_field(dbg_info_src, - debug_info->comp->arg_full_path, - bt_field_structure_borrow_member_field_by_name( - debug_info_field, "bin"), - debug_info->log_level, debug_info->self_comp); - fill_debug_info_func_field(dbg_info_src, - bt_field_structure_borrow_member_field_by_name( - debug_info_field, "func"), - debug_info->log_level, debug_info->self_comp); - fill_debug_info_src_field(dbg_info_src, - debug_info->comp->arg_full_path, - bt_field_structure_borrow_member_field_by_name( - debug_info_field, "src"), - debug_info->log_level, debug_info->self_comp); -} - -static -void fill_debug_info_event_if_needed(struct debug_info_msg_iter *debug_it, - const bt_event *in_event, bt_event *out_event) -{ - bt_field *out_common_ctx_field, *out_debug_info_field; - const bt_field *vpid_field, *ip_field, *in_common_ctx_field; - const bt_field_class *in_common_ctx_fc; - struct debug_info *debug_info; - uint64_t vpid; - int64_t ip; - gchar *debug_info_field_name = - debug_it->debug_info_component->arg_debug_info_field_name; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_common_ctx_field = bt_event_borrow_common_context_field_const( - in_event); - if (!in_common_ctx_field) { - /* - * There is no event common context so no need to add debug - * info field. - */ - goto end; - } - - in_common_ctx_fc = bt_field_borrow_class_const(in_common_ctx_field); - if (!is_event_common_ctx_dbg_info_compatible(in_common_ctx_fc, - debug_it->ir_maps->debug_info_field_class_name)) { - /* - * The input event common context does not have the necessary - * fields to resolve debug information. - */ - goto end; - } - - /* Borrow the debug-info field. */ - out_common_ctx_field = bt_event_borrow_common_context_field(out_event); - if (!out_common_ctx_field) { - goto end; - } - - out_debug_info_field = bt_field_structure_borrow_member_field_by_name( - out_common_ctx_field, debug_info_field_name); - - vpid_field = bt_field_structure_borrow_member_field_by_name_const( - out_common_ctx_field, VPID_FIELD_NAME); - ip_field = bt_field_structure_borrow_member_field_by_name_const( - out_common_ctx_field, IP_FIELD_NAME); - - vpid = bt_field_integer_signed_get_value(vpid_field); - ip = bt_field_integer_unsigned_get_value(ip_field); - - /* - * Borrow the debug_info structure needed for the source - * resolving. - */ - debug_info = g_hash_table_lookup(debug_it->debug_info_map, - bt_stream_borrow_trace_const( - bt_event_borrow_stream_const(in_event))); - - if (debug_info) { - /* - * Perform the debug-info resolving and set the event fields - * accordingly. - */ - fill_debug_info_field(debug_info, vpid, ip, out_debug_info_field); - } else { - BT_COMP_LOGD("No debug information for this trace. Setting debug " - "info fields to empty strings."); - fill_debug_info_field_empty(out_debug_info_field, - log_level, self_comp); - } -end: - return; -} - -static -void update_event_statedump_if_needed(struct debug_info_msg_iter *debug_it, - const bt_event *in_event) -{ - const bt_field *event_common_ctx; - const bt_field_class *event_common_ctx_fc; - const bt_event_class *in_event_class = bt_event_borrow_class_const(in_event); - - /* - * If the event is an lttng_ust_statedump event AND has the right event - * common context fields update the debug-info view for this process. - */ - event_common_ctx = bt_event_borrow_common_context_field_const(in_event); - if (!event_common_ctx) { - goto end; - } - - event_common_ctx_fc = bt_field_borrow_class_const(event_common_ctx); - if (is_event_common_ctx_dbg_info_compatible(event_common_ctx_fc, - debug_it->ir_maps->debug_info_field_class_name)) { - /* Checkout if it might be a one of lttng ust statedump events. */ - const char *in_event_name = bt_event_class_get_name(in_event_class); - if (strncmp(in_event_name, LTTNG_UST_STATEDUMP_PREFIX, - strlen(LTTNG_UST_STATEDUMP_PREFIX)) == 0) { - /* Handle statedump events. */ - handle_event_statedump(debug_it, in_event); - } - } -end: - return; -} - -static -bt_message *handle_event_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_clock_snapshot *cs; - const bt_clock_class *default_cc; - const bt_packet *in_packet; - const bt_stream *in_stream; - const bt_stream *out_stream; - bt_event_class *out_event_class; - bt_packet *out_packet = NULL; - bt_event *out_event; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - bt_message *out_message = NULL; - - /* Borrow the input event and its event class. */ - const bt_event *in_event = - bt_message_event_borrow_event_const(in_message); - const bt_event_class *in_event_class = - bt_event_borrow_class_const(in_event); - - update_event_statedump_if_needed(debug_it, in_event); - - out_event_class = trace_ir_mapping_borrow_mapped_event_class( - debug_it->ir_maps, in_event_class); - if (!out_event_class) { - out_event_class = trace_ir_mapping_create_new_mapped_event_class( - debug_it->ir_maps, in_event_class); - } - BT_ASSERT_DBG(out_event_class); - - /* Borrow the input stream. */ - in_stream = bt_event_borrow_stream_const(in_event); - BT_ASSERT_DBG(in_stream); - out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps, - in_stream); - BT_ASSERT_DBG(in_stream); - - /* Borrow the input and output packets. */ - in_packet = bt_event_borrow_packet_const(in_event); - if (in_packet) { - out_packet = trace_ir_mapping_borrow_mapped_packet( - debug_it->ir_maps, in_packet); - } - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_event_class_borrow_stream_class_const(in_event_class)); - if (default_cc) { - /* Borrow event clock snapshot. */ - cs = bt_message_event_borrow_default_clock_snapshot_const( - in_message); - - /* Create an output event message. */ - if (out_packet) { - out_message = - bt_message_event_create_with_packet_and_default_clock_snapshot( - debug_it->input_iterator, - out_event_class, out_packet, - bt_clock_snapshot_get_value(cs)); - } else { - out_message = - bt_message_event_create_with_default_clock_snapshot( - debug_it->input_iterator, - out_event_class, out_stream, - bt_clock_snapshot_get_value(cs)); - } - } else { - if (out_packet) { - out_message = bt_message_event_create_with_packet( - debug_it->input_iterator, out_event_class, - out_packet); - } else { - out_message = bt_message_event_create( - debug_it->input_iterator, out_event_class, - out_stream); - } - } - - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output event message."); - goto error; - } - - out_event = bt_message_event_borrow_event(out_message); - - /* Copy the original fields to the output event. */ - if (copy_event_content(in_event, out_event, log_level, self_comp) != - DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying event message content output event message: " - "in-ev-addr=%p, out-ev-addr=%p", in_event, out_event); - goto error; - } - - /* - * Try to set the debug-info fields based on debug information that is - * gathered so far. - */ - fill_debug_info_event_if_needed(debug_it, in_event, out_event); - - goto end; - -error: - BT_MESSAGE_PUT_REF_AND_RESET(out_message); -end: - return out_message; -} - -static -bt_message *handle_stream_begin_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_stream *in_stream; - bt_message *out_message; - bt_stream *out_stream; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_stream = bt_message_stream_beginning_borrow_stream_const(in_message); - BT_ASSERT(in_stream); - - /* Create a duplicated output stream. */ - out_stream = trace_ir_mapping_create_new_mapped_stream( - debug_it->ir_maps, in_stream); - if (!out_stream) { - out_message = NULL; - goto error; - } - - /* Create an output stream beginning message. */ - out_message = bt_message_stream_beginning_create( - debug_it->input_iterator, out_stream); - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output stream beginning message: " - "out-s-addr=%p", out_stream); - } -error: - return out_message; -} - -static -bt_message *handle_stream_end_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_stream *in_stream; - bt_message *out_message = NULL; - bt_stream *out_stream; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_stream = bt_message_stream_end_borrow_stream_const(in_message); - BT_ASSERT(in_stream); - - out_stream = trace_ir_mapping_borrow_mapped_stream( - debug_it->ir_maps, in_stream); - BT_ASSERT(out_stream); - - /* Create an output stream end message. */ - out_message = bt_message_stream_end_create(debug_it->input_iterator, - out_stream); - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output stream end message: " - "out-s-addr=%p", out_stream); - goto end; - } - - /* Remove stream from trace mapping hashtable. */ - trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream); - -end: - return out_message; -} - -static -bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - bool has_default_clock_snapshot; - const bt_clock_snapshot *cs; - bt_message *out_message = NULL; - bt_packet *out_packet; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - const bt_packet *in_packet = - bt_message_packet_beginning_borrow_packet_const(in_message); - BT_ASSERT(in_packet); - - /* This packet should not be already mapped. */ - BT_ASSERT(!trace_ir_mapping_borrow_mapped_packet( - debug_it->ir_maps, in_packet)); - - out_packet = trace_ir_mapping_create_new_mapped_packet(debug_it->ir_maps, - in_packet); - - BT_ASSERT(out_packet); - - has_default_clock_snapshot = - bt_stream_class_packets_have_beginning_default_clock_snapshot( - bt_stream_borrow_class_const( - bt_packet_borrow_stream_const(in_packet))); - if (has_default_clock_snapshot) { - /* Borrow clock snapshot. */ - cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const( - in_message); - - /* Create an output packet beginning message. */ - out_message = bt_message_packet_beginning_create_with_default_clock_snapshot( - debug_it->input_iterator, out_packet, - bt_clock_snapshot_get_value(cs)); - } else { - out_message = bt_message_packet_beginning_create( - debug_it->input_iterator, out_packet); - } - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output packet beginning message: " - "out-p-addr=%p", out_packet); - } - - return out_message; -} - -static -bt_message *handle_packet_end_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - bool has_default_clock_snapshot; - const bt_clock_snapshot *cs; - const bt_packet *in_packet; - bt_message *out_message = NULL; - bt_packet *out_packet; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_packet = bt_message_packet_end_borrow_packet_const(in_message); - BT_ASSERT(in_packet); - - out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps, in_packet); - BT_ASSERT(out_packet); - - has_default_clock_snapshot = - bt_stream_class_packets_have_end_default_clock_snapshot( - bt_stream_borrow_class_const( - bt_packet_borrow_stream_const(in_packet))); - if (has_default_clock_snapshot) { - /* Borrow clock snapshot. */ - cs = bt_message_packet_end_borrow_default_clock_snapshot_const( - in_message); - - /* Create an outpute packet end message. */ - out_message = bt_message_packet_end_create_with_default_clock_snapshot( - debug_it->input_iterator, out_packet, - bt_clock_snapshot_get_value(cs)); - } else { - out_message = bt_message_packet_end_create( - debug_it->input_iterator, out_packet); - } - - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output packet end message: " - "out-p-addr=%p", out_packet); - goto end; - } - - /* Remove packet from data mapping hashtable. */ - trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet); - -end: - return out_message; -} - -static -bt_message *handle_msg_iterator_inactivity(const bt_message *in_message) -{ - /* - * This message type can be forwarded directly because it does - * not refer to any objects in the trace class. - */ - bt_message_get_ref(in_message); - return (bt_message*) in_message; -} - -static -bt_message *handle_discarded_events_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_clock_snapshot *begin_cs, *end_cs; - const bt_stream *in_stream; - bool has_default_clock_snapshots; - uint64_t discarded_events, begin_cs_value, end_cs_value; - bt_property_availability prop_avail; - bt_message *out_message = NULL; - bt_stream *out_stream; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_stream = bt_message_discarded_events_borrow_stream_const( - in_message); - BT_ASSERT(in_stream); - - out_stream = trace_ir_mapping_borrow_mapped_stream( debug_it->ir_maps, - in_stream); - BT_ASSERT(out_stream); - - has_default_clock_snapshots = - bt_stream_class_discarded_events_have_default_clock_snapshots( - bt_stream_borrow_class_const(in_stream)); - if (has_default_clock_snapshots) { - begin_cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const( - in_message); - end_cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const( - in_message); - - begin_cs_value = bt_clock_snapshot_get_value(begin_cs); - end_cs_value = bt_clock_snapshot_get_value(end_cs); - - out_message = bt_message_discarded_events_create_with_default_clock_snapshots( - debug_it->input_iterator, out_stream, - begin_cs_value, end_cs_value); - } else { - out_message = bt_message_discarded_events_create( - debug_it->input_iterator, out_stream); - } - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output discarded events message: " - "out-s-addr=%p", out_stream); - goto error; - } - - prop_avail = bt_message_discarded_events_get_count(in_message, - &discarded_events); - - if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { - bt_message_discarded_events_set_count(out_message, - discarded_events); - } - -error: - return out_message; -} - -static -bt_message *handle_discarded_packets_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_clock_snapshot *begin_cs, *end_cs; - bool has_default_clock_snapshots; - const bt_stream *in_stream; - uint64_t discarded_packets, begin_cs_value, end_cs_value; - bt_property_availability prop_avail; - bt_message *out_message = NULL; - bt_stream *out_stream; - bt_logging_level log_level = debug_it->log_level; - bt_self_component *self_comp = debug_it->self_comp; - - in_stream = bt_message_discarded_packets_borrow_stream_const( - in_message); - BT_ASSERT(in_stream); - - out_stream = trace_ir_mapping_borrow_mapped_stream( debug_it->ir_maps, - in_stream); - BT_ASSERT(out_stream); - - has_default_clock_snapshots = - bt_stream_class_discarded_packets_have_default_clock_snapshots( - bt_stream_borrow_class_const(in_stream)); - if (has_default_clock_snapshots) { - begin_cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const( - in_message); - - end_cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const( - in_message); - - begin_cs_value = bt_clock_snapshot_get_value(begin_cs); - end_cs_value = bt_clock_snapshot_get_value(end_cs); - - out_message = bt_message_discarded_packets_create_with_default_clock_snapshots( - debug_it->input_iterator, out_stream, - begin_cs_value, end_cs_value); - } else { - out_message = bt_message_discarded_packets_create( - debug_it->input_iterator, out_stream); - } - if (!out_message) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output discarded packet message: " - "out-s-addr=%p", out_stream); - goto error; - } - - prop_avail = bt_message_discarded_packets_get_count(in_message, - &discarded_packets); - if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { - bt_message_discarded_packets_set_count(out_message, - discarded_packets); - } - -error: - return out_message; -} - -static -const bt_message *handle_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - bt_message *out_message = NULL; - - switch (bt_message_get_type(in_message)) { - case BT_MESSAGE_TYPE_EVENT: - out_message = handle_event_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_PACKET_BEGINNING: - out_message = handle_packet_begin_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_PACKET_END: - out_message = handle_packet_end_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_STREAM_BEGINNING: - out_message = handle_stream_begin_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_STREAM_END: - out_message = handle_stream_end_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY: - out_message = handle_msg_iterator_inactivity(in_message); - break; - case BT_MESSAGE_TYPE_DISCARDED_EVENTS: - out_message = handle_discarded_events_message(debug_it, in_message); - break; - case BT_MESSAGE_TYPE_DISCARDED_PACKETS: - out_message = handle_discarded_packets_message(debug_it, in_message); - break; - default: - bt_common_abort(); - break; - } - - return out_message; -} - -static -struct bt_param_validation_map_value_entry_descr debug_info_params[] = { - { "debug-info-field-name", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } }, - { "debug-info-dir", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } }, - { "target-prefix", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } }, - { "full-path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } }, - BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END -}; - -static -bt_component_class_initialize_method_status init_from_params( - struct debug_info_component *debug_info_component, - const bt_value *params) -{ - const bt_value *value; - bt_component_class_initialize_method_status status; - bt_logging_level log_level = debug_info_component->log_level; - enum bt_param_validation_status validation_status; - gchar *validate_error = NULL; - - validation_status = bt_param_validation_validate(params, - debug_info_params, &validate_error); - if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) { - status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; - goto end; - } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) { - status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; - BT_COMP_LOGE_APPEND_CAUSE(debug_info_component->self_comp, - "%s", validate_error); - goto end; - } - - BT_ASSERT(params); - - value = bt_value_map_borrow_entry_value_const(params, - "debug-info-field-name"); - if (value) { - debug_info_component->arg_debug_info_field_name = - g_strdup(bt_value_string_get(value)); - } else { - debug_info_component->arg_debug_info_field_name = - g_strdup(DEFAULT_DEBUG_INFO_FIELD_NAME); - } - - value = bt_value_map_borrow_entry_value_const(params, "debug-info-dir"); - if (value) { - debug_info_component->arg_debug_dir = - g_strdup(bt_value_string_get(value)); - } else { - debug_info_component->arg_debug_dir = NULL; - } - - - value = bt_value_map_borrow_entry_value_const(params, "target-prefix"); - if (value) { - debug_info_component->arg_target_prefix = - g_strdup(bt_value_string_get(value)); - } else { - debug_info_component->arg_target_prefix = NULL; - } - - value = bt_value_map_borrow_entry_value_const(params, "full-path"); - if (value) { - debug_info_component->arg_full_path = bt_value_bool_get(value); - } else { - debug_info_component->arg_full_path = BT_FALSE; - } - - status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; - -end: - g_free(validate_error); - - return status; -} - -bt_component_class_initialize_method_status debug_info_comp_init( - bt_self_component_filter *self_comp_flt, - bt_self_component_filter_configuration *config __attribute__((unused)), - const bt_value *params, void *init_method_data __attribute__((unused))) -{ - struct debug_info_component *debug_info_comp; - bt_component_class_initialize_method_status status = - BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; - bt_self_component_add_port_status add_port_status; - bt_self_component *self_comp = - bt_self_component_filter_as_self_component(self_comp_flt); - bt_logging_level log_level = bt_component_get_logging_level( - bt_self_component_as_component(self_comp)); - - BT_COMP_LOGI("Initializing debug_info component: " - "comp-addr=%p, params-addr=%p", self_comp, params); - - debug_info_comp = g_new0(struct debug_info_component, 1); - if (!debug_info_comp) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to allocate one debug_info component."); - goto error; - } - - debug_info_comp->log_level = log_level; - debug_info_comp->self_comp = self_comp; - debug_info_comp->self_comp_filter = self_comp_flt; - bt_self_component_set_data(self_comp, debug_info_comp); - - add_port_status = bt_self_component_filter_add_input_port( - self_comp_flt, "in", NULL, NULL); - if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { - status = (int) add_port_status; - goto error; - } - - add_port_status = bt_self_component_filter_add_output_port( - self_comp_flt, "out", NULL, NULL); - if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { - status = (int) add_port_status; - goto error; - } - - status = init_from_params(debug_info_comp, params); - if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot configure debug_info component: " - "debug_info-comp-addr=%p, params-addr=%p", - debug_info_comp, params); - goto error; - } - - goto end; - -error: - destroy_debug_info_comp(debug_info_comp); - bt_self_component_set_data(self_comp, NULL); - - if (status == BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) { - status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; - } -end: - return status; -} - -void debug_info_comp_finalize(bt_self_component_filter *self_comp_flt) -{ - struct debug_info_component *debug_info = - bt_self_component_get_data( - bt_self_component_filter_as_self_component( - self_comp_flt)); - bt_logging_level log_level = debug_info->log_level; - bt_self_component *self_comp = debug_info->self_comp; - - BT_COMP_LOGI("Finalizing debug_info self_component: comp-addr=%p", - self_comp); - - destroy_debug_info_comp(debug_info); -} - -bt_message_iterator_class_next_method_status debug_info_msg_iter_next( - bt_self_message_iterator *self_msg_iter, - const bt_message_array_const msgs, uint64_t capacity, - uint64_t *count) -{ - bt_message_iterator *upstream_iterator = NULL; - bt_message_iterator_next_status upstream_iterator_ret_status; - struct debug_info_msg_iter *debug_info_msg_iter; - struct debug_info_component *debug_info = NULL; - bt_message_iterator_class_next_method_status status; - bt_self_component *self_comp = NULL; - bt_message_array_const input_msgs; - const bt_message *out_message; - uint64_t curr_msg_idx, i; - - status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; - - self_comp = bt_self_message_iterator_borrow_component(self_msg_iter); - BT_ASSERT_DBG(self_comp); - - debug_info = bt_self_component_get_data(self_comp); - BT_ASSERT_DBG(debug_info); - - debug_info_msg_iter = bt_self_message_iterator_get_data(self_msg_iter); - BT_ASSERT_DBG(debug_info_msg_iter); - - upstream_iterator = debug_info_msg_iter->msg_iter; - BT_ASSERT_DBG(upstream_iterator); - - upstream_iterator_ret_status = - bt_message_iterator_next( - upstream_iterator, &input_msgs, count); - if (upstream_iterator_ret_status != - BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) { - /* - * No messages were returned. Not necessarily an error. - * Convert the upstream message iterator status to a - * self status. - */ - status = (int) upstream_iterator_ret_status; - goto end; - } - - /* - * There should never be more received messages than the capacity we - * provided. - */ - BT_ASSERT_DBG(*count <= capacity); - - for (curr_msg_idx = 0; curr_msg_idx < *count; curr_msg_idx++) { - out_message = handle_message(debug_info_msg_iter, - input_msgs[curr_msg_idx]); - if (!out_message) { - goto handle_msg_error; - } - - msgs[curr_msg_idx] = out_message; - /* - * Drop our reference of the input message as we are done with - * it and created a output copy. - */ - bt_message_put_ref(input_msgs[curr_msg_idx]); - } - - goto end; - -handle_msg_error: - /* - * Drop references of all the output messages created before the - * failure. - */ - for (i = 0; i < curr_msg_idx; i++) { - bt_message_put_ref(msgs[i]); - } - - /* - * Drop references of all the input messages not dropped before the - * failure. - */ - for (i = curr_msg_idx; i < *count; i++) { - bt_message_put_ref(input_msgs[i]); - } - - status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR; - -end: - return status; -} - -static -void debug_info_msg_iter_destroy(struct debug_info_msg_iter *debug_info_msg_iter) -{ - if (!debug_info_msg_iter) { - goto end; - } - - if (debug_info_msg_iter->msg_iter) { - bt_message_iterator_put_ref( - debug_info_msg_iter->msg_iter); - } - - if (debug_info_msg_iter->ir_maps) { - trace_ir_maps_destroy(debug_info_msg_iter->ir_maps); - } - - if (debug_info_msg_iter->debug_info_map) { - g_hash_table_destroy(debug_info_msg_iter->debug_info_map); - } - - bt_fd_cache_fini(&debug_info_msg_iter->fd_cache); - g_free(debug_info_msg_iter); - -end: - return; -} - -bt_message_iterator_class_initialize_method_status debug_info_msg_iter_init( - bt_self_message_iterator *self_msg_iter, - bt_self_message_iterator_configuration *config, - bt_self_component_port_output *self_port __attribute__((unused))) -{ - bt_message_iterator_class_initialize_method_status status; - bt_message_iterator_create_from_message_iterator_status - msg_iter_status; - struct bt_self_component_port_input *input_port = NULL; - bt_message_iterator *upstream_iterator = NULL; - struct debug_info_msg_iter *debug_info_msg_iter = NULL; - gchar *debug_info_field_name; - int ret; - bt_self_component *self_comp = - bt_self_message_iterator_borrow_component(self_msg_iter); - bt_logging_level log_level = bt_component_get_logging_level( - bt_self_component_as_component(self_comp)); - - debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1); - if (!debug_info_msg_iter) { - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; - goto error; - } - - debug_info_msg_iter->log_level = log_level; - debug_info_msg_iter->self_comp = self_comp; - - debug_info_msg_iter->debug_info_component = - bt_self_component_get_data(self_comp); - - /* Borrow the upstream input port. */ - input_port = bt_self_component_filter_borrow_input_port_by_name( - debug_info_msg_iter->debug_info_component->self_comp_filter, - "in"); - if (!input_port) { - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; - goto error; - } - - /* Create an iterator on the upstream component. */ - msg_iter_status = bt_message_iterator_create_from_message_iterator( - self_msg_iter, input_port, &upstream_iterator); - if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK) { - status = (int) msg_iter_status; - goto error; - } - - BT_MESSAGE_ITERATOR_MOVE_REF( - debug_info_msg_iter->msg_iter, upstream_iterator); - - /* Create hashtable that will contain debug info mapping. */ - debug_info_msg_iter->debug_info_map = g_hash_table_new_full( - g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, - (GDestroyNotify) debug_info_destroy); - if (!debug_info_msg_iter->debug_info_map) { - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; - goto error; - } - - debug_info_field_name = - debug_info_msg_iter->debug_info_component->arg_debug_info_field_name; - - debug_info_msg_iter->ir_maps = trace_ir_maps_create(self_comp, - debug_info_field_name, log_level); - if (!debug_info_msg_iter->ir_maps) { - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; - goto error; - } - - ret = bt_fd_cache_init(&debug_info_msg_iter->fd_cache, log_level); - if (ret) { - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; - goto error; - } - - bt_self_message_iterator_configuration_set_can_seek_forward(config, - bt_message_iterator_can_seek_forward( - debug_info_msg_iter->msg_iter)); - - bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter); - debug_info_msg_iter->input_iterator = self_msg_iter; - - status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; - goto end; - -error: - debug_info_msg_iter_destroy(debug_info_msg_iter); - -end: - return status; -} - -bt_message_iterator_class_can_seek_beginning_method_status -debug_info_msg_iter_can_seek_beginning(bt_self_message_iterator *self_msg_iter, - bt_bool *can_seek) -{ - struct debug_info_msg_iter *debug_info_msg_iter = - bt_self_message_iterator_get_data(self_msg_iter); - BT_ASSERT(debug_info_msg_iter); - - return (int) bt_message_iterator_can_seek_beginning( - debug_info_msg_iter->msg_iter, can_seek); -} - -bt_message_iterator_class_seek_beginning_method_status -debug_info_msg_iter_seek_beginning(bt_self_message_iterator *self_msg_iter) -{ - struct debug_info_msg_iter *debug_info_msg_iter = - bt_self_message_iterator_get_data(self_msg_iter); - bt_message_iterator_class_seek_beginning_method_status status = - BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK; - bt_message_iterator_seek_beginning_status seek_beg_status; - - BT_ASSERT(debug_info_msg_iter); - - /* Ask the upstream component to seek to the beginning. */ - seek_beg_status = bt_message_iterator_seek_beginning( - debug_info_msg_iter->msg_iter); - if (seek_beg_status != BT_MESSAGE_ITERATOR_SEEK_BEGINNING_STATUS_OK) { - status = (int) seek_beg_status; - goto end; - } - - /* Clear this iterator data. */ - trace_ir_maps_clear(debug_info_msg_iter->ir_maps); - g_hash_table_remove_all(debug_info_msg_iter->debug_info_map); - -end: - return status; -} - -void debug_info_msg_iter_finalize(bt_self_message_iterator *it) -{ - struct debug_info_msg_iter *debug_info_msg_iter; - - debug_info_msg_iter = bt_self_message_iterator_get_data(it); - BT_ASSERT(debug_info_msg_iter); - - debug_info_msg_iter_destroy(debug_info_msg_iter); -} diff --git a/src/plugins/lttng-utils/debug-info/debug-info.cpp b/src/plugins/lttng-utils/debug-info/debug-info.cpp new file mode 100644 index 00000000..409350b4 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/debug-info.cpp @@ -0,0 +1,2095 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * Copyright (c) 2015 Antoine Busque + * Copyright (c) 2016 Jérémie Galarneau + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Debug Information State Tracker + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP self_comp +#define BT_LOG_OUTPUT_LEVEL log_level +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO" +#include "logging/comp-logging.h" + +#include + +#include + +#include "common/assert.h" +#include "common/common.h" +#include "fd-cache/fd-cache.hpp" + +#include "bin-info.hpp" +#include "debug-info.hpp" +#include "trace-ir-data-copy.hpp" +#include "trace-ir-mapping.hpp" +#include "trace-ir-metadata-copy.hpp" +#include "utils.hpp" +#include "plugins/common/param-validation/param-validation.h" + +#define DEFAULT_DEBUG_INFO_FIELD_NAME "debug_info" +#define LTTNG_UST_STATEDUMP_PREFIX "lttng_ust" + +struct debug_info_component { + bt_logging_level log_level; + bt_self_component *self_comp; + bt_self_component_filter *self_comp_filter; + gchar *arg_debug_dir; + gchar *arg_debug_info_field_name; + gchar *arg_target_prefix; + bt_bool arg_full_path; +}; + +struct debug_info_msg_iter { + bt_logging_level log_level; + struct debug_info_component *debug_info_component; + bt_self_message_iterator *input_iterator; + bt_self_component *self_comp; + bt_message_iterator *msg_iter; + + struct trace_ir_maps *ir_maps; + /* in_trace -> debug_info_mapping. */ + GHashTable *debug_info_map; + + struct bt_fd_cache fd_cache; +}; + +struct debug_info_source { + /* Strings are owned by debug_info_source. */ + gchar *func; + /* + * Store the line number as a string so that the allocation and + * conversion to string is only done once. + */ + gchar *line_no; + gchar *src_path; + /* short_src_path points inside src_path, no need to free. */ + const gchar *short_src_path; + gchar *bin_path; + /* short_bin_path points inside bin_path, no need to free. */ + const gchar *short_bin_path; + /* + * Location within the binary. Either absolute (@0x1234) or + * relative (+0x4321). + */ + gchar *bin_loc; +}; + +struct proc_debug_info_sources { + /* + * Hash table: base address (pointer to uint64_t) to bin info; owned by + * proc_debug_info_sources. + */ + GHashTable *baddr_to_bin_info; + + /* + * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *); + * owned by proc_debug_info_sources. + */ + GHashTable *ip_to_debug_info_src; +}; + +struct debug_info { + bt_logging_level log_level; + bt_self_component *self_comp; + struct debug_info_component *comp; + const bt_trace *input_trace; + bt_listener_id destruction_listener_id; + + /* + * Hash table of VPIDs (pointer to int64_t) to + * (struct proc_debug_info_sources*); owned by debug_info. + */ + GHashTable *vpid_to_proc_dbg_info_src; + GQuark q_statedump_bin_info; + GQuark q_statedump_debug_link; + GQuark q_statedump_build_id; + GQuark q_statedump_start; + GQuark q_dl_open; + GQuark q_lib_load; + GQuark q_lib_unload; + struct bt_fd_cache *fd_cache; /* Weak ref. Owned by the iterator. */ +}; + +static +int debug_info_init(struct debug_info *info) +{ + info->q_statedump_bin_info = g_quark_from_string( + "lttng_ust_statedump:bin_info"); + info->q_statedump_debug_link = g_quark_from_string( + "lttng_ust_statedump:debug_link"); + info->q_statedump_build_id = g_quark_from_string( + "lttng_ust_statedump:build_id"); + info->q_statedump_start = g_quark_from_string( + "lttng_ust_statedump:start"); + info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen"); + info->q_lib_load = g_quark_from_string("lttng_ust_lib:load"); + info->q_lib_unload = g_quark_from_string("lttng_ust_lib:unload"); + + return bin_info_init(info->log_level, info->self_comp); +} + +static +void debug_info_source_destroy(struct debug_info_source *debug_info_src) +{ + if (!debug_info_src) { + return; + } + + g_free(debug_info_src->func); + g_free(debug_info_src->line_no); + g_free(debug_info_src->src_path); + g_free(debug_info_src->bin_path); + g_free(debug_info_src->bin_loc); + g_free(debug_info_src); +} + +static +struct debug_info_source *debug_info_source_create_from_bin( + struct bin_info *bin, uint64_t ip, + bt_self_component *self_comp) +{ + int ret; + struct debug_info_source *debug_info_src = NULL; + struct source_location *src_loc = NULL; + bt_logging_level log_level; + + BT_ASSERT(bin); + + log_level = bin->log_level; + + debug_info_src = g_new0(struct debug_info_source, 1); + + if (!debug_info_src) { + goto end; + } + + /* Lookup function name */ + ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func); + if (ret) { + goto error; + } + + /* Can't retrieve src_loc from ELF, or could not find binary, skip. */ + if (!bin->is_elf_only || !debug_info_src->func) { + /* Lookup source location */ + ret = bin_info_lookup_source_location(bin, ip, &src_loc); + if (ret) { + BT_COMP_LOGI("Failed to lookup source location: ret=%d", ret); + } + } + + if (src_loc) { + debug_info_src->line_no = + g_strdup_printf("%" PRId64, src_loc->line_no); + if (!debug_info_src->line_no) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error occurred when setting `line_no` field."); + goto error; + } + + if (src_loc->filename) { + debug_info_src->src_path = g_strdup(src_loc->filename); + if (!debug_info_src->src_path) { + goto error; + } + + debug_info_src->short_src_path = get_filename_from_path( + debug_info_src->src_path); + } + source_location_destroy(src_loc); + } + + if (bin->elf_path) { + debug_info_src->bin_path = g_strdup(bin->elf_path); + if (!debug_info_src->bin_path) { + goto error; + } + + debug_info_src->short_bin_path = get_filename_from_path( + debug_info_src->bin_path); + + ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc)); + if (ret) { + goto error; + } + } + +end: + return debug_info_src; + +error: + debug_info_source_destroy(debug_info_src); + return NULL; +} + +static +void proc_debug_info_sources_destroy( + struct proc_debug_info_sources *proc_dbg_info_src) +{ + if (!proc_dbg_info_src) { + return; + } + + if (proc_dbg_info_src->baddr_to_bin_info) { + g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info); + } + + if (proc_dbg_info_src->ip_to_debug_info_src) { + g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src); + } + + g_free(proc_dbg_info_src); +} + +static +struct proc_debug_info_sources *proc_debug_info_sources_create(void) +{ + struct proc_debug_info_sources *proc_dbg_info_src = NULL; + + proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1); + if (!proc_dbg_info_src) { + goto end; + } + + proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full( + g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, + (GDestroyNotify) bin_info_destroy); + if (!proc_dbg_info_src->baddr_to_bin_info) { + goto error; + } + + proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full( + g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, + (GDestroyNotify) debug_info_source_destroy); + if (!proc_dbg_info_src->ip_to_debug_info_src) { + goto error; + } + +end: + return proc_dbg_info_src; + +error: + proc_debug_info_sources_destroy(proc_dbg_info_src); + return NULL; +} + +static +struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry( + GHashTable *ht, int64_t vpid) +{ + gpointer key = g_new0(int64_t, 1); + struct proc_debug_info_sources *proc_dbg_info_src = NULL; + + if (!key) { + goto end; + } + + *((int64_t *) key) = vpid; + + /* Exists? Return it */ + proc_dbg_info_src = static_cast(g_hash_table_lookup(ht, key)); + if (proc_dbg_info_src) { + goto end; + } + + /* Otherwise, create and return it */ + proc_dbg_info_src = proc_debug_info_sources_create(); + if (!proc_dbg_info_src) { + goto end; + } + + g_hash_table_insert(ht, key, proc_dbg_info_src); + /* Ownership passed to ht */ + key = NULL; +end: + g_free(key); + return proc_dbg_info_src; +} + +static inline +const bt_field *event_borrow_payload_field(const bt_event *event, + const char *field_name) +{ + const bt_field *event_payload, *field; + + event_payload = bt_event_borrow_payload_field_const(event); + BT_ASSERT_DBG(event_payload); + + field = bt_field_structure_borrow_member_field_by_name_const( + event_payload, field_name); + return field; +} + +static inline +const bt_field *event_borrow_common_context_field(const bt_event *event, + const char *field_name) +{ + const bt_field *event_common_ctx, *field = NULL; + + event_common_ctx = bt_event_borrow_common_context_field_const(event); + if (!event_common_ctx) { + goto end; + } + + field = bt_field_structure_borrow_member_field_by_name_const( + event_common_ctx, field_name); + +end: + return field; +} + +static inline +void event_get_common_context_signed_integer_field_value( + const bt_event *event, const char *field_name, int64_t *value) +{ + *value = bt_field_integer_signed_get_value( + event_borrow_common_context_field(event, field_name)); +} + +static inline +void event_get_payload_build_id_length(const bt_event *event, + const char *field_name, uint64_t *build_id_len) +{ + const bt_field *build_id_field; + const bt_field_class *build_id_field_class; + + build_id_field = event_borrow_payload_field(event, field_name); + build_id_field_class = bt_field_borrow_class_const(build_id_field); + + BT_ASSERT(bt_field_class_get_type(build_id_field_class) == + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD || + bt_field_class_get_type(build_id_field_class) == + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD); + BT_ASSERT(bt_field_class_get_type( + bt_field_class_array_borrow_element_field_class_const( + build_id_field_class)) == + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER); + + *build_id_len = bt_field_array_get_length(build_id_field); +} + +static inline +void event_get_payload_build_id_value(const bt_event *event, + const char *field_name, uint8_t *build_id) +{ + const bt_field *curr_field, *build_id_field; + const bt_field_class *build_id_field_class; + uint64_t i, build_id_len; + + build_id_field = event_borrow_payload_field(event, field_name); + build_id_field_class = bt_field_borrow_class_const(build_id_field); + + BT_ASSERT(bt_field_class_get_type(build_id_field_class) == + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD || + bt_field_class_get_type(build_id_field_class) == + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD); + BT_ASSERT(bt_field_class_get_type( + bt_field_class_array_borrow_element_field_class_const( + build_id_field_class)) == + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER); + + build_id_len = bt_field_array_get_length(build_id_field); + + for (i = 0; i < build_id_len; i++) { + curr_field = bt_field_array_borrow_element_field_by_index_const( + build_id_field, i); + + build_id[i] = bt_field_integer_unsigned_get_value(curr_field); + } +} + +static +void event_get_payload_unsigned_integer_field_value(const bt_event *event, + const char *field_name, uint64_t *value) +{ + *value = bt_field_integer_unsigned_get_value( + event_borrow_payload_field(event, field_name)); +} + +static +void event_get_payload_string_field_value(const bt_event *event, + const char *field_name, const char **value) +{ + *value = bt_field_string_get_value( + event_borrow_payload_field(event, field_name)); +} + +static inline +bool event_has_payload_field(const bt_event *event, + const char *field_name) +{ + return event_borrow_payload_field(event, field_name); +} + +static +struct debug_info_source *proc_debug_info_sources_get_entry( + struct debug_info *debug_info, + struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip) +{ + struct debug_info_source *debug_info_src = NULL; + gpointer key = g_new0(uint64_t, 1); + GHashTableIter iter; + gpointer baddr, value; + + if (!key) { + goto end; + } + + *((uint64_t *) key) = ip; + + /* Look in IP to debug infos hash table first. */ + debug_info_src = static_cast(g_hash_table_lookup( + proc_dbg_info_src->ip_to_debug_info_src, key)); + if (debug_info_src) { + goto end; + } + + /* Check in all bin_infos. */ + g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info); + + while (g_hash_table_iter_next(&iter, &baddr, &value)) + { + struct bin_info *bin = static_cast(value); + + if (!bin_info_has_address(bin, ip)) { + continue; + } + + /* + * Found; add it to cache. + * + * FIXME: this should be bounded in size (and implement + * a caching policy), and entries should be prunned when + * libraries are unmapped. + */ + debug_info_src = debug_info_source_create_from_bin(bin, ip, + debug_info->self_comp); + if (debug_info_src) { + g_hash_table_insert( + proc_dbg_info_src->ip_to_debug_info_src, key, + debug_info_src); + /* Ownership passed to ht. */ + key = NULL; + } + break; + } + +end: + free(key); + return debug_info_src; +} + +static +struct debug_info_source *debug_info_query(struct debug_info *debug_info, + int64_t vpid, uint64_t ip) +{ + struct debug_info_source *dbg_info_src = NULL; + struct proc_debug_info_sources *proc_dbg_info_src; + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + goto end; + } + + dbg_info_src = proc_debug_info_sources_get_entry(debug_info, + proc_dbg_info_src, ip); + +end: + return dbg_info_src; +} + +static +struct debug_info *debug_info_create(struct debug_info_component *comp, + const bt_trace *trace, struct bt_fd_cache *fdc) +{ + int ret; + struct debug_info *debug_info; + + BT_ASSERT(comp); + BT_ASSERT(trace); + BT_ASSERT(fdc); + + debug_info = g_new0(struct debug_info, 1); + if (!debug_info) { + goto end; + } + + debug_info->log_level = comp->log_level; + debug_info->self_comp = comp->self_comp; + debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full( + g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, + (GDestroyNotify) proc_debug_info_sources_destroy); + if (!debug_info->vpid_to_proc_dbg_info_src) { + goto error; + } + + debug_info->comp = comp; + ret = debug_info_init(debug_info); + if (ret) { + goto error; + } + + debug_info->input_trace = trace; + debug_info->fd_cache = fdc; + +end: + return debug_info; +error: + g_free(debug_info); + return NULL; +} + +static +void debug_info_destroy(struct debug_info *debug_info) +{ + bt_logging_level log_level; + bt_self_component *self_comp; + bt_trace_remove_listener_status remove_listener_status; + if (!debug_info) { + goto end; + } + + log_level = debug_info->log_level; + self_comp = debug_info->self_comp; + + if (debug_info->vpid_to_proc_dbg_info_src) { + g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src); + } + + remove_listener_status = bt_trace_remove_destruction_listener( + debug_info->input_trace, + debug_info->destruction_listener_id); + if (remove_listener_status != BT_TRACE_REMOVE_LISTENER_STATUS_OK) { + BT_COMP_LOGE("Trace destruction listener removal failed."); + bt_current_thread_clear_error(); + } + + g_free(debug_info); +end: + return; +} + +static +void handle_event_statedump_build_id(struct debug_info *debug_info, + const bt_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + uint64_t build_id_len, baddr; + uint8_t *build_id = NULL; + struct bin_info *bin; + int64_t vpid; + int ret = 0; + + event_get_common_context_signed_integer_field_value(event, + VPID_FIELD_NAME, &vpid); + event_get_payload_unsigned_integer_field_value(event, + BADDR_FIELD_NAME, &baddr); + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + goto end; + } + + bin = static_cast(g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, + (gpointer) &baddr)); + if (!bin) { + /* + * The build_id event comes after the bin has been + * created. If it isn't found, just ignore this event. + */ + goto end; + } + + event_get_payload_build_id_length(event, BUILD_ID_FIELD_NAME, + &build_id_len); + + build_id = g_new0(uint8_t, build_id_len); + if (!build_id) { + goto end; + } + + event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME, build_id); + + ret = bin_info_set_build_id(bin, build_id, build_id_len); + if (ret) { + goto end; + } + + /* + * Reset the is_elf_only flag in case it had been set + * previously, because we might find separate debug info using + * the new build id information. + */ + bin->is_elf_only = false; + +end: + g_free(build_id); + return; +} + +static +void handle_event_statedump_debug_link(struct debug_info *debug_info, + const bt_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + struct bin_info *bin = NULL; + int64_t vpid; + uint64_t baddr; + const char *filename = NULL; + uint32_t crc32; + uint64_t crc_field_value; + + event_get_common_context_signed_integer_field_value(event, + VPID_FIELD_NAME, &vpid); + + event_get_payload_unsigned_integer_field_value(event, + BADDR_FIELD_NAME, &baddr); + + event_get_payload_unsigned_integer_field_value(event, + CRC32_FIELD_NAME, &crc_field_value); + + crc32 = (uint32_t) crc_field_value; + + event_get_payload_string_field_value(event, + FILENAME_FIELD_NAME, &filename); + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + goto end; + } + + bin = static_cast(g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, + (gpointer) &baddr)); + if (!bin) { + /* + * The debug_link event comes after the bin has been + * created. If it isn't found, just ignore this event. + */ + goto end; + } + + bin_info_set_debug_link(bin, filename, crc32); + +end: + return; +} + +static +void handle_bin_info_event(struct debug_info *debug_info, + const bt_event *event, bool has_pic_field) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + struct bin_info *bin; + uint64_t baddr, memsz; + int64_t vpid; + const char *path; + gpointer key = NULL; + bool is_pic; + + event_get_payload_unsigned_integer_field_value(event, + MEMSZ_FIELD_NAME, &memsz); + if (memsz == 0) { + /* Ignore VDSO. */ + goto end; + } + + event_get_payload_unsigned_integer_field_value(event, + BADDR_FIELD_NAME, &baddr); + + /* + * This field is not produced by the dlopen event emitted before + * lttng-ust 2.9. + */ + if (!event_has_payload_field(event, PATH_FIELD_NAME)) { + goto end; + } + event_get_payload_string_field_value(event, PATH_FIELD_NAME, &path); + + if (has_pic_field) { + uint64_t is_pic_field_value; + + event_get_payload_unsigned_integer_field_value(event, + IS_PIC_FIELD_NAME, &is_pic_field_value); + is_pic = is_pic_field_value == 1; + } else { + /* + * dlopen has no is_pic field, because the shared + * object is always PIC. + */ + is_pic = true; + } + + event_get_common_context_signed_integer_field_value(event, + VPID_FIELD_NAME, &vpid); + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + goto end; + } + + key = g_new0(uint64_t, 1); + if (!key) { + goto end; + } + + *((uint64_t *) key) = baddr; + + bin = static_cast(g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, key)); + if (bin) { + goto end; + } + + bin = bin_info_create(debug_info->fd_cache, path, baddr, memsz, is_pic, + debug_info->comp->arg_debug_dir, + debug_info->comp->arg_target_prefix, + debug_info->log_level, debug_info->self_comp); + if (!bin) { + goto end; + } + + g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, key, bin); + /* Ownership passed to ht. */ + key = NULL; + +end: + g_free(key); + return; +} + +static inline +void handle_event_statedump_bin_info(struct debug_info *debug_info, + const bt_event *event) +{ + handle_bin_info_event(debug_info, event, true); +} + +static inline +void handle_event_lib_load(struct debug_info *debug_info, + const bt_event *event) +{ + handle_bin_info_event(debug_info, event, false); +} + +static +void handle_event_lib_unload(struct debug_info *debug_info, + const bt_event *event) +{ + gboolean ret; + struct proc_debug_info_sources *proc_dbg_info_src; + uint64_t baddr; + int64_t vpid; + + event_get_payload_unsigned_integer_field_value(event, BADDR_FIELD_NAME, + &baddr); + + event_get_common_context_signed_integer_field_value(event, + VPID_FIELD_NAME, &vpid); + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + /* + * It's an unload event for a library for which no load event + * was previously received. + */ + goto end; + } + + ret = g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info, + (gpointer) &baddr); + BT_ASSERT(ret); +end: + return; +} + +static +void handle_event_statedump_start(struct debug_info *debug_info, + const bt_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + int64_t vpid; + + event_get_common_context_signed_integer_field_value( + event, VPID_FIELD_NAME, &vpid); + + proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( + debug_info->vpid_to_proc_dbg_info_src, vpid); + if (!proc_dbg_info_src) { + goto end; + } + + g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info); + g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src); + +end: + return; +} + +static +void trace_debug_info_remove_func(const bt_trace *in_trace, void *data) +{ + struct debug_info_msg_iter *debug_it = static_cast(data); + if (debug_it->debug_info_map) { + gboolean ret; + ret = g_hash_table_remove(debug_it->debug_info_map, + (gpointer) in_trace); + BT_ASSERT(ret); + } +} + +static +void handle_event_statedump(struct debug_info_msg_iter *debug_it, + const bt_event *event) +{ + const bt_event_class *event_class; + const char *event_name; + GQuark q_event_name; + const bt_trace *trace; + struct debug_info *debug_info; + + BT_ASSERT(debug_it); + BT_ASSERT(event); + + event_class = bt_event_borrow_class_const(event); + + event_name = bt_event_class_get_name(event_class); + + trace = bt_stream_borrow_trace_const( + bt_event_borrow_stream_const(event)); + + debug_info = static_cast(g_hash_table_lookup(debug_it->debug_info_map, trace)); + if (!debug_info) { + bt_trace_add_listener_status add_listener_status; + + debug_info = debug_info_create(debug_it->debug_info_component, + trace, &debug_it->fd_cache); + g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace, + debug_info); + add_listener_status = bt_trace_add_destruction_listener( + trace, trace_debug_info_remove_func, debug_it, + &debug_info->destruction_listener_id); + BT_ASSERT(add_listener_status == BT_TRACE_ADD_LISTENER_STATUS_OK); + } + + q_event_name = g_quark_try_string(event_name); + + if (q_event_name == debug_info->q_statedump_bin_info) { + /* State dump */ + handle_event_statedump_bin_info(debug_info, event); + } else if (q_event_name == debug_info->q_dl_open || + q_event_name == debug_info->q_lib_load) { + /* + * dl_open and lib_load events are both checked for since + * only dl_open was produced as of lttng-ust 2.8. + * + * lib_load, which is produced from lttng-ust 2.9+, is a lot + * more reliable since it will be emitted when other functions + * of the dlopen family are called (e.g. dlmopen) and when + * library are transitively loaded. + */ + handle_event_lib_load(debug_info, event); + } else if (q_event_name == debug_info->q_statedump_start) { + /* Start state dump */ + handle_event_statedump_start(debug_info, event); + } else if (q_event_name == debug_info->q_statedump_debug_link) { + /* Debug link info */ + handle_event_statedump_debug_link(debug_info, event); + } else if (q_event_name == debug_info->q_statedump_build_id) { + /* Build ID info */ + handle_event_statedump_build_id(debug_info, event); + } else if (q_event_name == debug_info->q_lib_unload) { + handle_event_lib_unload(debug_info, event); + } + + return; +} + +static +void destroy_debug_info_comp(struct debug_info_component *debug_info) +{ + if (!debug_info) { + return; + } + + g_free(debug_info->arg_debug_dir); + g_free(debug_info->arg_debug_info_field_name); + g_free(debug_info->arg_target_prefix); + g_free(debug_info); +} + +static +void fill_debug_info_bin_field(struct debug_info_source *dbg_info_src, + bool full_path, bt_field *curr_field, + bt_logging_level log_level, bt_self_component *self_comp) +{ + bt_field_string_set_value_status set_status; + bt_field_string_append_status append_status; + + BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == + BT_FIELD_CLASS_TYPE_STRING); + + if (dbg_info_src) { + if (full_path) { + set_status = bt_field_string_set_value(curr_field, + dbg_info_src->bin_path); + } else { + set_status = bt_field_string_set_value(curr_field, + dbg_info_src->short_bin_path); + } + if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set path component of `bin` " + "curr_field field's value: str-fc-addr=%p", + curr_field); + bt_current_thread_clear_error(); + } + + append_status = bt_field_string_append(curr_field, + dbg_info_src->bin_loc); + if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { + BT_COMP_LOGE("Cannot set bin location component of `bin` " + "curr_field field's value: str-fc-addr=%p", + curr_field); + bt_current_thread_clear_error(); + } + } else { + set_status = bt_field_string_set_value(curr_field, ""); + if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `bin` curr_field field's value: " + "str-fc-addr=%p", curr_field); + bt_current_thread_clear_error(); + } + } +} + +static +void fill_debug_info_func_field(struct debug_info_source *dbg_info_src, + bt_field *curr_field, bt_logging_level log_level, + bt_self_component *self_comp) +{ + bt_field_string_set_value_status status; + + BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == + BT_FIELD_CLASS_TYPE_STRING); + if (dbg_info_src && dbg_info_src->func) { + status = bt_field_string_set_value(curr_field, + dbg_info_src->func); + } else { + status = bt_field_string_set_value(curr_field, ""); + } + if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `func` curr_field field's value: " + "str-fc-addr=%p", curr_field); + bt_current_thread_clear_error(); + } +} + +static +void fill_debug_info_src_field(struct debug_info_source *dbg_info_src, + bool full_path, bt_field *curr_field, + bt_logging_level log_level, + bt_self_component *self_comp) +{ + bt_field_string_set_value_status set_status; + bt_field_string_append_status append_status; + + BT_ASSERT_DBG(bt_field_get_class_type(curr_field) == + BT_FIELD_CLASS_TYPE_STRING); + + if (dbg_info_src && dbg_info_src->src_path) { + if (full_path) { + set_status = bt_field_string_set_value(curr_field, + dbg_info_src->src_path); + } else { + set_status = bt_field_string_set_value(curr_field, + dbg_info_src->short_src_path); + } + if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set path component of `src` " + "curr_field field's value: str-fc-addr=%p", + curr_field); + bt_current_thread_clear_error(); + } + + append_status = bt_field_string_append(curr_field, ":"); + if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { + BT_COMP_LOGE("Cannot set colon component of `src` " + "curr_field field's value: str-fc-addr=%p", + curr_field); + bt_current_thread_clear_error(); + } + + append_status = bt_field_string_append(curr_field, + dbg_info_src->line_no); + if (append_status != BT_FIELD_STRING_APPEND_STATUS_OK) { + BT_COMP_LOGE("Cannot set line number component of `src` " + "curr_field field's value: str-fc-addr=%p", + curr_field); + bt_current_thread_clear_error(); + } + } else { + set_status = bt_field_string_set_value(curr_field, ""); + if (set_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `src` curr_field field's value: " + "str-fc-addr=%p", curr_field); + bt_current_thread_clear_error(); + } + } +} + +static +void fill_debug_info_field_empty(bt_field *debug_info_field, + bt_logging_level log_level, bt_self_component *self_comp) +{ + bt_field_string_set_value_status status; + bt_field *bin_field, *func_field, *src_field; + + BT_ASSERT_DBG(bt_field_get_class_type(debug_info_field) == + BT_FIELD_CLASS_TYPE_STRUCTURE); + + bin_field = bt_field_structure_borrow_member_field_by_name( + debug_info_field, "bin"); + func_field = bt_field_structure_borrow_member_field_by_name( + debug_info_field, "func"); + src_field = bt_field_structure_borrow_member_field_by_name( + debug_info_field, "src"); + + BT_ASSERT_DBG(bt_field_get_class_type(bin_field) == + BT_FIELD_CLASS_TYPE_STRING); + BT_ASSERT_DBG(bt_field_get_class_type(func_field) == + BT_FIELD_CLASS_TYPE_STRING); + BT_ASSERT_DBG(bt_field_get_class_type(src_field) == + BT_FIELD_CLASS_TYPE_STRING); + + status = bt_field_string_set_value(bin_field, ""); + if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `bin` field's value: " + "str-fc-addr=%p", bin_field); + bt_current_thread_clear_error(); + } + + status = bt_field_string_set_value(func_field, ""); + if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `func` field's value: " + "str-fc-addr=%p", func_field); + bt_current_thread_clear_error(); + } + + status = bt_field_string_set_value(src_field, ""); + if (status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE("Cannot set `src` field's value: " + "str-fc-addr=%p", src_field); + bt_current_thread_clear_error(); + } +} +static +void fill_debug_info_field(struct debug_info *debug_info, int64_t vpid, + uint64_t ip, bt_field *debug_info_field) +{ + struct debug_info_source *dbg_info_src; + const bt_field_class *debug_info_fc; + + BT_ASSERT_DBG(bt_field_get_class_type(debug_info_field) == + BT_FIELD_CLASS_TYPE_STRUCTURE); + + debug_info_fc = bt_field_borrow_class_const(debug_info_field); + + BT_ASSERT_DBG(bt_field_class_structure_get_member_count( + debug_info_fc) == 3); + + dbg_info_src = debug_info_query(debug_info, vpid, ip); + + fill_debug_info_bin_field(dbg_info_src, + debug_info->comp->arg_full_path, + bt_field_structure_borrow_member_field_by_name( + debug_info_field, "bin"), + debug_info->log_level, debug_info->self_comp); + fill_debug_info_func_field(dbg_info_src, + bt_field_structure_borrow_member_field_by_name( + debug_info_field, "func"), + debug_info->log_level, debug_info->self_comp); + fill_debug_info_src_field(dbg_info_src, + debug_info->comp->arg_full_path, + bt_field_structure_borrow_member_field_by_name( + debug_info_field, "src"), + debug_info->log_level, debug_info->self_comp); +} + +static +void fill_debug_info_event_if_needed(struct debug_info_msg_iter *debug_it, + const bt_event *in_event, bt_event *out_event) +{ + bt_field *out_common_ctx_field, *out_debug_info_field; + const bt_field *vpid_field, *ip_field, *in_common_ctx_field; + const bt_field_class *in_common_ctx_fc; + struct debug_info *debug_info; + uint64_t vpid; + int64_t ip; + gchar *debug_info_field_name = + debug_it->debug_info_component->arg_debug_info_field_name; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_common_ctx_field = bt_event_borrow_common_context_field_const( + in_event); + if (!in_common_ctx_field) { + /* + * There is no event common context so no need to add debug + * info field. + */ + goto end; + } + + in_common_ctx_fc = bt_field_borrow_class_const(in_common_ctx_field); + if (!is_event_common_ctx_dbg_info_compatible(in_common_ctx_fc, + debug_it->ir_maps->debug_info_field_class_name)) { + /* + * The input event common context does not have the necessary + * fields to resolve debug information. + */ + goto end; + } + + /* Borrow the debug-info field. */ + out_common_ctx_field = bt_event_borrow_common_context_field(out_event); + if (!out_common_ctx_field) { + goto end; + } + + out_debug_info_field = bt_field_structure_borrow_member_field_by_name( + out_common_ctx_field, debug_info_field_name); + + vpid_field = bt_field_structure_borrow_member_field_by_name_const( + out_common_ctx_field, VPID_FIELD_NAME); + ip_field = bt_field_structure_borrow_member_field_by_name_const( + out_common_ctx_field, IP_FIELD_NAME); + + vpid = bt_field_integer_signed_get_value(vpid_field); + ip = bt_field_integer_unsigned_get_value(ip_field); + + /* + * Borrow the debug_info structure needed for the source + * resolving. + */ + debug_info = static_cast(g_hash_table_lookup(debug_it->debug_info_map, + bt_stream_borrow_trace_const( + bt_event_borrow_stream_const(in_event)))); + + if (debug_info) { + /* + * Perform the debug-info resolving and set the event fields + * accordingly. + */ + fill_debug_info_field(debug_info, vpid, ip, out_debug_info_field); + } else { + BT_COMP_LOGD("No debug information for this trace. Setting debug " + "info fields to empty strings."); + fill_debug_info_field_empty(out_debug_info_field, + log_level, self_comp); + } +end: + return; +} + +static +void update_event_statedump_if_needed(struct debug_info_msg_iter *debug_it, + const bt_event *in_event) +{ + const bt_field *event_common_ctx; + const bt_field_class *event_common_ctx_fc; + const bt_event_class *in_event_class = bt_event_borrow_class_const(in_event); + + /* + * If the event is an lttng_ust_statedump event AND has the right event + * common context fields update the debug-info view for this process. + */ + event_common_ctx = bt_event_borrow_common_context_field_const(in_event); + if (!event_common_ctx) { + goto end; + } + + event_common_ctx_fc = bt_field_borrow_class_const(event_common_ctx); + if (is_event_common_ctx_dbg_info_compatible(event_common_ctx_fc, + debug_it->ir_maps->debug_info_field_class_name)) { + /* Checkout if it might be a one of lttng ust statedump events. */ + const char *in_event_name = bt_event_class_get_name(in_event_class); + if (strncmp(in_event_name, LTTNG_UST_STATEDUMP_PREFIX, + strlen(LTTNG_UST_STATEDUMP_PREFIX)) == 0) { + /* Handle statedump events. */ + handle_event_statedump(debug_it, in_event); + } + } +end: + return; +} + +static +bt_message *handle_event_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_clock_snapshot *cs; + const bt_clock_class *default_cc; + const bt_packet *in_packet; + const bt_stream *in_stream; + const bt_stream *out_stream; + bt_event_class *out_event_class; + bt_packet *out_packet = NULL; + bt_event *out_event; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + bt_message *out_message = NULL; + + /* Borrow the input event and its event class. */ + const bt_event *in_event = + bt_message_event_borrow_event_const(in_message); + const bt_event_class *in_event_class = + bt_event_borrow_class_const(in_event); + + update_event_statedump_if_needed(debug_it, in_event); + + out_event_class = trace_ir_mapping_borrow_mapped_event_class( + debug_it->ir_maps, in_event_class); + if (!out_event_class) { + out_event_class = trace_ir_mapping_create_new_mapped_event_class( + debug_it->ir_maps, in_event_class); + } + BT_ASSERT_DBG(out_event_class); + + /* Borrow the input stream. */ + in_stream = bt_event_borrow_stream_const(in_event); + BT_ASSERT_DBG(in_stream); + out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps, + in_stream); + BT_ASSERT_DBG(in_stream); + + /* Borrow the input and output packets. */ + in_packet = bt_event_borrow_packet_const(in_event); + if (in_packet) { + out_packet = trace_ir_mapping_borrow_mapped_packet( + debug_it->ir_maps, in_packet); + } + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_event_class_borrow_stream_class_const(in_event_class)); + if (default_cc) { + /* Borrow event clock snapshot. */ + cs = bt_message_event_borrow_default_clock_snapshot_const( + in_message); + + /* Create an output event message. */ + if (out_packet) { + out_message = + bt_message_event_create_with_packet_and_default_clock_snapshot( + debug_it->input_iterator, + out_event_class, out_packet, + bt_clock_snapshot_get_value(cs)); + } else { + out_message = + bt_message_event_create_with_default_clock_snapshot( + debug_it->input_iterator, + out_event_class, out_stream, + bt_clock_snapshot_get_value(cs)); + } + } else { + if (out_packet) { + out_message = bt_message_event_create_with_packet( + debug_it->input_iterator, out_event_class, + out_packet); + } else { + out_message = bt_message_event_create( + debug_it->input_iterator, out_event_class, + out_stream); + } + } + + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output event message."); + goto error; + } + + out_event = bt_message_event_borrow_event(out_message); + + /* Copy the original fields to the output event. */ + if (copy_event_content(in_event, out_event, log_level, self_comp) != + DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying event message content output event message: " + "in-ev-addr=%p, out-ev-addr=%p", in_event, out_event); + goto error; + } + + /* + * Try to set the debug-info fields based on debug information that is + * gathered so far. + */ + fill_debug_info_event_if_needed(debug_it, in_event, out_event); + + goto end; + +error: + BT_MESSAGE_PUT_REF_AND_RESET(out_message); +end: + return out_message; +} + +static +bt_message *handle_stream_begin_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_stream *in_stream; + bt_message *out_message; + bt_stream *out_stream; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_stream = bt_message_stream_beginning_borrow_stream_const(in_message); + BT_ASSERT(in_stream); + + /* Create a duplicated output stream. */ + out_stream = trace_ir_mapping_create_new_mapped_stream( + debug_it->ir_maps, in_stream); + if (!out_stream) { + out_message = NULL; + goto error; + } + + /* Create an output stream beginning message. */ + out_message = bt_message_stream_beginning_create( + debug_it->input_iterator, out_stream); + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output stream beginning message: " + "out-s-addr=%p", out_stream); + } +error: + return out_message; +} + +static +bt_message *handle_stream_end_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_stream *in_stream; + bt_message *out_message = NULL; + bt_stream *out_stream; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_stream = bt_message_stream_end_borrow_stream_const(in_message); + BT_ASSERT(in_stream); + + out_stream = trace_ir_mapping_borrow_mapped_stream( + debug_it->ir_maps, in_stream); + BT_ASSERT(out_stream); + + /* Create an output stream end message. */ + out_message = bt_message_stream_end_create(debug_it->input_iterator, + out_stream); + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output stream end message: " + "out-s-addr=%p", out_stream); + goto end; + } + + /* Remove stream from trace mapping hashtable. */ + trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream); + +end: + return out_message; +} + +static +bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + bool has_default_clock_snapshot; + const bt_clock_snapshot *cs; + bt_message *out_message = NULL; + bt_packet *out_packet; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + const bt_packet *in_packet = + bt_message_packet_beginning_borrow_packet_const(in_message); + BT_ASSERT(in_packet); + + /* This packet should not be already mapped. */ + BT_ASSERT(!trace_ir_mapping_borrow_mapped_packet( + debug_it->ir_maps, in_packet)); + + out_packet = trace_ir_mapping_create_new_mapped_packet(debug_it->ir_maps, + in_packet); + + BT_ASSERT(out_packet); + + has_default_clock_snapshot = + bt_stream_class_packets_have_beginning_default_clock_snapshot( + bt_stream_borrow_class_const( + bt_packet_borrow_stream_const(in_packet))); + if (has_default_clock_snapshot) { + /* Borrow clock snapshot. */ + cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const( + in_message); + + /* Create an output packet beginning message. */ + out_message = bt_message_packet_beginning_create_with_default_clock_snapshot( + debug_it->input_iterator, out_packet, + bt_clock_snapshot_get_value(cs)); + } else { + out_message = bt_message_packet_beginning_create( + debug_it->input_iterator, out_packet); + } + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output packet beginning message: " + "out-p-addr=%p", out_packet); + } + + return out_message; +} + +static +bt_message *handle_packet_end_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + bool has_default_clock_snapshot; + const bt_clock_snapshot *cs; + const bt_packet *in_packet; + bt_message *out_message = NULL; + bt_packet *out_packet; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_packet = bt_message_packet_end_borrow_packet_const(in_message); + BT_ASSERT(in_packet); + + out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps, in_packet); + BT_ASSERT(out_packet); + + has_default_clock_snapshot = + bt_stream_class_packets_have_end_default_clock_snapshot( + bt_stream_borrow_class_const( + bt_packet_borrow_stream_const(in_packet))); + if (has_default_clock_snapshot) { + /* Borrow clock snapshot. */ + cs = bt_message_packet_end_borrow_default_clock_snapshot_const( + in_message); + + /* Create an outpute packet end message. */ + out_message = bt_message_packet_end_create_with_default_clock_snapshot( + debug_it->input_iterator, out_packet, + bt_clock_snapshot_get_value(cs)); + } else { + out_message = bt_message_packet_end_create( + debug_it->input_iterator, out_packet); + } + + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output packet end message: " + "out-p-addr=%p", out_packet); + goto end; + } + + /* Remove packet from data mapping hashtable. */ + trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet); + +end: + return out_message; +} + +static +bt_message *handle_msg_iterator_inactivity(const bt_message *in_message) +{ + /* + * This message type can be forwarded directly because it does + * not refer to any objects in the trace class. + */ + bt_message_get_ref(in_message); + return (bt_message*) in_message; +} + +static +bt_message *handle_discarded_events_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_clock_snapshot *begin_cs, *end_cs; + const bt_stream *in_stream; + bool has_default_clock_snapshots; + uint64_t discarded_events, begin_cs_value, end_cs_value; + bt_property_availability prop_avail; + bt_message *out_message = NULL; + bt_stream *out_stream; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_stream = bt_message_discarded_events_borrow_stream_const( + in_message); + BT_ASSERT(in_stream); + + out_stream = trace_ir_mapping_borrow_mapped_stream( debug_it->ir_maps, + in_stream); + BT_ASSERT(out_stream); + + has_default_clock_snapshots = + bt_stream_class_discarded_events_have_default_clock_snapshots( + bt_stream_borrow_class_const(in_stream)); + if (has_default_clock_snapshots) { + begin_cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const( + in_message); + end_cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const( + in_message); + + begin_cs_value = bt_clock_snapshot_get_value(begin_cs); + end_cs_value = bt_clock_snapshot_get_value(end_cs); + + out_message = bt_message_discarded_events_create_with_default_clock_snapshots( + debug_it->input_iterator, out_stream, + begin_cs_value, end_cs_value); + } else { + out_message = bt_message_discarded_events_create( + debug_it->input_iterator, out_stream); + } + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output discarded events message: " + "out-s-addr=%p", out_stream); + goto error; + } + + prop_avail = bt_message_discarded_events_get_count(in_message, + &discarded_events); + + if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { + bt_message_discarded_events_set_count(out_message, + discarded_events); + } + +error: + return out_message; +} + +static +bt_message *handle_discarded_packets_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_clock_snapshot *begin_cs, *end_cs; + bool has_default_clock_snapshots; + const bt_stream *in_stream; + uint64_t discarded_packets, begin_cs_value, end_cs_value; + bt_property_availability prop_avail; + bt_message *out_message = NULL; + bt_stream *out_stream; + bt_logging_level log_level = debug_it->log_level; + bt_self_component *self_comp = debug_it->self_comp; + + in_stream = bt_message_discarded_packets_borrow_stream_const( + in_message); + BT_ASSERT(in_stream); + + out_stream = trace_ir_mapping_borrow_mapped_stream( debug_it->ir_maps, + in_stream); + BT_ASSERT(out_stream); + + has_default_clock_snapshots = + bt_stream_class_discarded_packets_have_default_clock_snapshots( + bt_stream_borrow_class_const(in_stream)); + if (has_default_clock_snapshots) { + begin_cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const( + in_message); + + end_cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const( + in_message); + + begin_cs_value = bt_clock_snapshot_get_value(begin_cs); + end_cs_value = bt_clock_snapshot_get_value(end_cs); + + out_message = bt_message_discarded_packets_create_with_default_clock_snapshots( + debug_it->input_iterator, out_stream, + begin_cs_value, end_cs_value); + } else { + out_message = bt_message_discarded_packets_create( + debug_it->input_iterator, out_stream); + } + if (!out_message) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output discarded packet message: " + "out-s-addr=%p", out_stream); + goto error; + } + + prop_avail = bt_message_discarded_packets_get_count(in_message, + &discarded_packets); + if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { + bt_message_discarded_packets_set_count(out_message, + discarded_packets); + } + +error: + return out_message; +} + +static +const bt_message *handle_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + bt_message *out_message = NULL; + + switch (bt_message_get_type(in_message)) { + case BT_MESSAGE_TYPE_EVENT: + out_message = handle_event_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_PACKET_BEGINNING: + out_message = handle_packet_begin_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_PACKET_END: + out_message = handle_packet_end_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_STREAM_BEGINNING: + out_message = handle_stream_begin_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_STREAM_END: + out_message = handle_stream_end_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY: + out_message = handle_msg_iterator_inactivity(in_message); + break; + case BT_MESSAGE_TYPE_DISCARDED_EVENTS: + out_message = handle_discarded_events_message(debug_it, in_message); + break; + case BT_MESSAGE_TYPE_DISCARDED_PACKETS: + out_message = handle_discarded_packets_message(debug_it, in_message); + break; + default: + bt_common_abort(); + break; + } + + return out_message; +} + +static +struct bt_param_validation_map_value_entry_descr debug_info_params[] = { + { "debug-info-field-name", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, bt_param_validation_value_descr::makeString() }, + { "debug-info-dir", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, bt_param_validation_value_descr::makeString() }, + { "target-prefix", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, bt_param_validation_value_descr::makeString() }, + { "full-path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, bt_param_validation_value_descr::makeBool() }, + BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END +}; + +static +bt_component_class_initialize_method_status init_from_params( + struct debug_info_component *debug_info_component, + const bt_value *params) +{ + const bt_value *value; + bt_component_class_initialize_method_status status; + bt_logging_level log_level = debug_info_component->log_level; + enum bt_param_validation_status validation_status; + gchar *validate_error = NULL; + + validation_status = bt_param_validation_validate(params, + debug_info_params, &validate_error); + if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) { + status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; + goto end; + } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) { + status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; + BT_COMP_LOGE_APPEND_CAUSE(debug_info_component->self_comp, + "%s", validate_error); + goto end; + } + + BT_ASSERT(params); + + value = bt_value_map_borrow_entry_value_const(params, + "debug-info-field-name"); + if (value) { + debug_info_component->arg_debug_info_field_name = + g_strdup(bt_value_string_get(value)); + } else { + debug_info_component->arg_debug_info_field_name = + g_strdup(DEFAULT_DEBUG_INFO_FIELD_NAME); + } + + value = bt_value_map_borrow_entry_value_const(params, "debug-info-dir"); + if (value) { + debug_info_component->arg_debug_dir = + g_strdup(bt_value_string_get(value)); + } else { + debug_info_component->arg_debug_dir = NULL; + } + + + value = bt_value_map_borrow_entry_value_const(params, "target-prefix"); + if (value) { + debug_info_component->arg_target_prefix = + g_strdup(bt_value_string_get(value)); + } else { + debug_info_component->arg_target_prefix = NULL; + } + + value = bt_value_map_borrow_entry_value_const(params, "full-path"); + if (value) { + debug_info_component->arg_full_path = bt_value_bool_get(value); + } else { + debug_info_component->arg_full_path = BT_FALSE; + } + + status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; + +end: + g_free(validate_error); + + return status; +} + +bt_component_class_initialize_method_status debug_info_comp_init( + bt_self_component_filter *self_comp_flt, + bt_self_component_filter_configuration *config __attribute__((unused)), + const bt_value *params, void *init_method_data __attribute__((unused))) +{ + struct debug_info_component *debug_info_comp; + bt_component_class_initialize_method_status status = + BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; + bt_self_component_add_port_status add_port_status; + bt_self_component *self_comp = + bt_self_component_filter_as_self_component(self_comp_flt); + bt_logging_level log_level = bt_component_get_logging_level( + bt_self_component_as_component(self_comp)); + + BT_COMP_LOGI("Initializing debug_info component: " + "comp-addr=%p, params-addr=%p", self_comp, params); + + debug_info_comp = g_new0(struct debug_info_component, 1); + if (!debug_info_comp) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to allocate one debug_info component."); + goto error; + } + + debug_info_comp->log_level = log_level; + debug_info_comp->self_comp = self_comp; + debug_info_comp->self_comp_filter = self_comp_flt; + bt_self_component_set_data(self_comp, debug_info_comp); + + add_port_status = bt_self_component_filter_add_input_port( + self_comp_flt, "in", NULL, NULL); + if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { + status = static_cast(add_port_status); + goto error; + } + + add_port_status = bt_self_component_filter_add_output_port( + self_comp_flt, "out", NULL, NULL); + if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { + status = static_cast(add_port_status); + goto error; + } + + status = init_from_params(debug_info_comp, params); + if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot configure debug_info component: " + "debug_info-comp-addr=%p, params-addr=%p", + debug_info_comp, params); + goto error; + } + + goto end; + +error: + destroy_debug_info_comp(debug_info_comp); + bt_self_component_set_data(self_comp, NULL); + + if (status == BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) { + status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; + } +end: + return status; +} + +void debug_info_comp_finalize(bt_self_component_filter *self_comp_flt) +{ + struct debug_info_component *debug_info = + static_cast(bt_self_component_get_data( + bt_self_component_filter_as_self_component( + self_comp_flt))); + bt_logging_level log_level = debug_info->log_level; + bt_self_component *self_comp = debug_info->self_comp; + + BT_COMP_LOGI("Finalizing debug_info self_component: comp-addr=%p", + self_comp); + + destroy_debug_info_comp(debug_info); +} + +bt_message_iterator_class_next_method_status debug_info_msg_iter_next( + bt_self_message_iterator *self_msg_iter, + const bt_message_array_const msgs, uint64_t capacity, + uint64_t *count) +{ + bt_message_iterator *upstream_iterator = NULL; + bt_message_iterator_next_status upstream_iterator_ret_status; + struct debug_info_msg_iter *debug_info_msg_iter; + struct debug_info_component *debug_info = NULL; + bt_message_iterator_class_next_method_status status; + bt_self_component *self_comp = NULL; + bt_message_array_const input_msgs; + const bt_message *out_message; + uint64_t curr_msg_idx, i; + + status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; + + self_comp = bt_self_message_iterator_borrow_component(self_msg_iter); + BT_ASSERT_DBG(self_comp); + + debug_info = static_cast(bt_self_component_get_data(self_comp)); + BT_ASSERT_DBG(debug_info); + + debug_info_msg_iter = static_cast(bt_self_message_iterator_get_data(self_msg_iter)); + BT_ASSERT_DBG(debug_info_msg_iter); + + upstream_iterator = debug_info_msg_iter->msg_iter; + BT_ASSERT_DBG(upstream_iterator); + + upstream_iterator_ret_status = + bt_message_iterator_next( + upstream_iterator, &input_msgs, count); + if (upstream_iterator_ret_status != + BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) { + /* + * No messages were returned. Not necessarily an error. + * Convert the upstream message iterator status to a + * self status. + */ + status = static_cast(upstream_iterator_ret_status); + goto end; + } + + /* + * There should never be more received messages than the capacity we + * provided. + */ + BT_ASSERT_DBG(*count <= capacity); + + for (curr_msg_idx = 0; curr_msg_idx < *count; curr_msg_idx++) { + out_message = handle_message(debug_info_msg_iter, + input_msgs[curr_msg_idx]); + if (!out_message) { + goto handle_msg_error; + } + + msgs[curr_msg_idx] = out_message; + /* + * Drop our reference of the input message as we are done with + * it and created a output copy. + */ + bt_message_put_ref(input_msgs[curr_msg_idx]); + } + + goto end; + +handle_msg_error: + /* + * Drop references of all the output messages created before the + * failure. + */ + for (i = 0; i < curr_msg_idx; i++) { + bt_message_put_ref(msgs[i]); + } + + /* + * Drop references of all the input messages not dropped before the + * failure. + */ + for (i = curr_msg_idx; i < *count; i++) { + bt_message_put_ref(input_msgs[i]); + } + + status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR; + +end: + return status; +} + +static +void debug_info_msg_iter_destroy(struct debug_info_msg_iter *debug_info_msg_iter) +{ + if (!debug_info_msg_iter) { + goto end; + } + + if (debug_info_msg_iter->msg_iter) { + bt_message_iterator_put_ref( + debug_info_msg_iter->msg_iter); + } + + if (debug_info_msg_iter->ir_maps) { + trace_ir_maps_destroy(debug_info_msg_iter->ir_maps); + } + + if (debug_info_msg_iter->debug_info_map) { + g_hash_table_destroy(debug_info_msg_iter->debug_info_map); + } + + bt_fd_cache_fini(&debug_info_msg_iter->fd_cache); + g_free(debug_info_msg_iter); + +end: + return; +} + +bt_message_iterator_class_initialize_method_status debug_info_msg_iter_init( + bt_self_message_iterator *self_msg_iter, + bt_self_message_iterator_configuration *config, + bt_self_component_port_output *self_port __attribute__((unused))) +{ + bt_message_iterator_class_initialize_method_status status; + bt_message_iterator_create_from_message_iterator_status + msg_iter_status; + struct bt_self_component_port_input *input_port = NULL; + bt_message_iterator *upstream_iterator = NULL; + struct debug_info_msg_iter *debug_info_msg_iter = NULL; + gchar *debug_info_field_name; + int ret; + bt_self_component *self_comp = + bt_self_message_iterator_borrow_component(self_msg_iter); + bt_logging_level log_level = bt_component_get_logging_level( + bt_self_component_as_component(self_comp)); + + debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1); + if (!debug_info_msg_iter) { + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; + goto error; + } + + debug_info_msg_iter->log_level = log_level; + debug_info_msg_iter->self_comp = self_comp; + + debug_info_msg_iter->debug_info_component = + static_cast(bt_self_component_get_data(self_comp)); + + /* Borrow the upstream input port. */ + input_port = bt_self_component_filter_borrow_input_port_by_name( + debug_info_msg_iter->debug_info_component->self_comp_filter, + "in"); + if (!input_port) { + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; + goto error; + } + + /* Create an iterator on the upstream component. */ + msg_iter_status = bt_message_iterator_create_from_message_iterator( + self_msg_iter, input_port, &upstream_iterator); + if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK) { + status = static_cast(msg_iter_status); + goto error; + } + + BT_MESSAGE_ITERATOR_MOVE_REF( + debug_info_msg_iter->msg_iter, upstream_iterator); + + /* Create hashtable that will contain debug info mapping. */ + debug_info_msg_iter->debug_info_map = g_hash_table_new_full( + g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, + (GDestroyNotify) debug_info_destroy); + if (!debug_info_msg_iter->debug_info_map) { + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; + goto error; + } + + debug_info_field_name = + debug_info_msg_iter->debug_info_component->arg_debug_info_field_name; + + debug_info_msg_iter->ir_maps = trace_ir_maps_create(self_comp, + debug_info_field_name, log_level); + if (!debug_info_msg_iter->ir_maps) { + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; + goto error; + } + + ret = bt_fd_cache_init(&debug_info_msg_iter->fd_cache, log_level); + if (ret) { + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; + goto error; + } + + bt_self_message_iterator_configuration_set_can_seek_forward(config, + bt_message_iterator_can_seek_forward( + debug_info_msg_iter->msg_iter)); + + bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter); + debug_info_msg_iter->input_iterator = self_msg_iter; + + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; + goto end; + +error: + debug_info_msg_iter_destroy(debug_info_msg_iter); + +end: + return status; +} + +bt_message_iterator_class_can_seek_beginning_method_status +debug_info_msg_iter_can_seek_beginning(bt_self_message_iterator *self_msg_iter, + bt_bool *can_seek) +{ + struct debug_info_msg_iter *debug_info_msg_iter = + static_cast(bt_self_message_iterator_get_data(self_msg_iter)); + BT_ASSERT(debug_info_msg_iter); + + return static_cast(bt_message_iterator_can_seek_beginning( + debug_info_msg_iter->msg_iter, can_seek)); +} + +bt_message_iterator_class_seek_beginning_method_status +debug_info_msg_iter_seek_beginning(bt_self_message_iterator *self_msg_iter) +{ + struct debug_info_msg_iter *debug_info_msg_iter = + static_cast(bt_self_message_iterator_get_data(self_msg_iter)); + bt_message_iterator_class_seek_beginning_method_status status = + BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK; + bt_message_iterator_seek_beginning_status seek_beg_status; + + BT_ASSERT(debug_info_msg_iter); + + /* Ask the upstream component to seek to the beginning. */ + seek_beg_status = bt_message_iterator_seek_beginning( + debug_info_msg_iter->msg_iter); + if (seek_beg_status != BT_MESSAGE_ITERATOR_SEEK_BEGINNING_STATUS_OK) { + status = static_cast(seek_beg_status); + goto end; + } + + /* Clear this iterator data. */ + trace_ir_maps_clear(debug_info_msg_iter->ir_maps); + g_hash_table_remove_all(debug_info_msg_iter->debug_info_map); + +end: + return status; +} + +void debug_info_msg_iter_finalize(bt_self_message_iterator *it) +{ + struct debug_info_msg_iter *debug_info_msg_iter; + + debug_info_msg_iter = static_cast(bt_self_message_iterator_get_data(it)); + BT_ASSERT(debug_info_msg_iter); + + debug_info_msg_iter_destroy(debug_info_msg_iter); +} diff --git a/src/plugins/lttng-utils/debug-info/debug-info.h b/src/plugins/lttng-utils/debug-info/debug-info.h deleted file mode 100644 index 5877a056..00000000 --- a/src/plugins/lttng-utils/debug-info/debug-info.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2019 EfficiOS Inc. - * Copyright (c) 2015 Antoine Busque - * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com> - * - * Babeltrace - Debug information Plugin - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_H - -#include -#include - -#include - -#include "common/macros.h" - -#define VPID_FIELD_NAME "vpid" -#define IP_FIELD_NAME "ip" -#define BADDR_FIELD_NAME "baddr" -#define CRC32_FIELD_NAME "crc" -#define BUILD_ID_FIELD_NAME "build_id" -#define FILENAME_FIELD_NAME "filename" -#define IS_PIC_FIELD_NAME "is_pic" -#define MEMSZ_FIELD_NAME "memsz" -#define PATH_FIELD_NAME "path" - -bt_component_class_initialize_method_status debug_info_comp_init( - bt_self_component_filter *self_comp, - bt_self_component_filter_configuration *config, - const bt_value *params, void *init_method_data); - -void debug_info_comp_finalize(bt_self_component_filter *self_comp); - -bt_message_iterator_class_initialize_method_status debug_info_msg_iter_init( - bt_self_message_iterator *self_msg_iter, - bt_self_message_iterator_configuration *config, - bt_self_component_port_output *self_port); - -bt_message_iterator_class_next_method_status debug_info_msg_iter_next( - bt_self_message_iterator *self_msg_iter, - const bt_message_array_const msgs, uint64_t capacity, - uint64_t *count); - -bt_message_iterator_class_can_seek_beginning_method_status -debug_info_msg_iter_can_seek_beginning( - bt_self_message_iterator *message_iterator, - bt_bool *can_seek); - -bt_message_iterator_class_seek_beginning_method_status debug_info_msg_iter_seek_beginning( - bt_self_message_iterator *message_iterator); - -void debug_info_msg_iter_finalize(bt_self_message_iterator *it); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_H */ diff --git a/src/plugins/lttng-utils/debug-info/debug-info.hpp b/src/plugins/lttng-utils/debug-info/debug-info.hpp new file mode 100644 index 00000000..94183e6a --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/debug-info.hpp @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2019 EfficiOS Inc. + * Copyright (c) 2015 Antoine Busque + * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com> + * + * Babeltrace - Debug information Plugin + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_HPP + +#include +#include + +#include + +#include "common/macros.h" + +#define VPID_FIELD_NAME "vpid" +#define IP_FIELD_NAME "ip" +#define BADDR_FIELD_NAME "baddr" +#define CRC32_FIELD_NAME "crc" +#define BUILD_ID_FIELD_NAME "build_id" +#define FILENAME_FIELD_NAME "filename" +#define IS_PIC_FIELD_NAME "is_pic" +#define MEMSZ_FIELD_NAME "memsz" +#define PATH_FIELD_NAME "path" + +bt_component_class_initialize_method_status debug_info_comp_init( + bt_self_component_filter *self_comp, + bt_self_component_filter_configuration *config, + const bt_value *params, void *init_method_data); + +void debug_info_comp_finalize(bt_self_component_filter *self_comp); + +bt_message_iterator_class_initialize_method_status debug_info_msg_iter_init( + bt_self_message_iterator *self_msg_iter, + bt_self_message_iterator_configuration *config, + bt_self_component_port_output *self_port); + +bt_message_iterator_class_next_method_status debug_info_msg_iter_next( + bt_self_message_iterator *self_msg_iter, + const bt_message_array_const msgs, uint64_t capacity, + uint64_t *count); + +bt_message_iterator_class_can_seek_beginning_method_status +debug_info_msg_iter_can_seek_beginning( + bt_self_message_iterator *message_iterator, + bt_bool *can_seek); + +bt_message_iterator_class_seek_beginning_method_status debug_info_msg_iter_seek_beginning( + bt_self_message_iterator *message_iterator); + +void debug_info_msg_iter_finalize(bt_self_message_iterator *it); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DEBUG_INFO_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/dwarf.c b/src/plugins/lttng-utils/debug-info/dwarf.c deleted file mode 100644 index 20c605c8..00000000 --- a/src/plugins/lttng-utils/debug-info/dwarf.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2015 Antoine Busque - * - * Babeltrace - DWARF Information Reader - */ - -#include - -#include - -#include "dwarf.h" - -struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info) -{ - struct bt_dwarf_cu *cu; - - if (!dwarf_info) { - goto error; - } - - cu = g_new0(struct bt_dwarf_cu, 1); - if (!cu) { - goto error; - } - cu->dwarf_info = dwarf_info; - return cu; - -error: - return NULL; -} - -void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu) -{ - g_free(cu); -} - -int bt_dwarf_cu_next(struct bt_dwarf_cu *cu) -{ - int ret; - Dwarf_Off next_offset; - size_t cu_header_size; - - if (!cu) { - ret = -1; - goto end; - } - - ret = dwarf_nextcu(cu->dwarf_info, cu->next_offset, &next_offset, - &cu_header_size, NULL, NULL, NULL); - if (ret) { - /* ret is -1 on error, 1 if no next CU. */ - goto end; - } - - cu->offset = cu->next_offset; - cu->next_offset = next_offset; - cu->header_size = cu_header_size; - -end: - return ret; -} - -struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu) -{ - Dwarf_Die *dwarf_die = NULL; - struct bt_dwarf_die *die = NULL; - - if (!cu) { - goto error; - } - - dwarf_die = g_new0(Dwarf_Die, 1); - if (!dwarf_die) { - goto error; - } - - dwarf_die = dwarf_offdie(cu->dwarf_info, cu->offset + cu->header_size, - dwarf_die); - if (!dwarf_die) { - goto error; - } - - die = g_new0(struct bt_dwarf_die, 1); - if (!die) { - goto error; - } - - die->cu = cu; - die->dwarf_die = dwarf_die; - die->depth = 0; - - return die; - -error: - g_free(dwarf_die); - g_free(die); - return NULL; -} - -void bt_dwarf_die_destroy(struct bt_dwarf_die *die) -{ - if (!die) { - return; - } - - g_free(die->dwarf_die); - g_free(die); -} - -int bt_dwarf_die_has_children(struct bt_dwarf_die *die) -{ - return dwarf_haschildren(die->dwarf_die); -} - -int bt_dwarf_die_child(struct bt_dwarf_die *die) -{ - int ret; - Dwarf_Die *child_die = NULL; - - if (!die) { - ret = -1; - goto error; - } - - child_die = g_new0(Dwarf_Die, 1); - if (!child_die) { - ret = -1; - goto error; - } - - ret = dwarf_child(die->dwarf_die, child_die); - if (ret) { - /* ret is -1 on error, 1 if no child DIE. */ - goto error; - } - - g_free(die->dwarf_die); - die->dwarf_die = child_die; - die->depth++; - return 0; - -error: - g_free(child_die); - return ret; -} - -int bt_dwarf_die_next(struct bt_dwarf_die *die) -{ - int ret; - Dwarf_Die *next_die = NULL; - - if (!die) { - ret = -1; - goto error; - } - - next_die = g_new0(Dwarf_Die, 1); - if (!next_die) { - ret = -1; - goto error; - } - - if (die->depth == 0) { - ret = dwarf_child(die->dwarf_die, next_die); - if (ret) { - /* ret is -1 on error, 1 if no child DIE. */ - goto error; - } - - die->depth = 1; - } else { - ret = dwarf_siblingof(die->dwarf_die, next_die); - if (ret) { - /* ret is -1 on error, 1 if we reached end of - * DIEs at this depth. */ - goto error; - } - } - - g_free(die->dwarf_die); - die->dwarf_die = next_die; - return 0; - -error: - g_free(next_die); - return ret; -} - -int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag) -{ - int _tag; - - if (!die || !tag) { - goto error; - } - - _tag = dwarf_tag(die->dwarf_die); - if (_tag == DW_TAG_invalid) { - goto error; - } - - *tag = _tag; - return 0; - -error: - return -1; -} - -int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name) -{ - const char *_name; - - if (!die || !name) { - goto error; - } - - _name = dwarf_diename(die->dwarf_die); - if (!_name) { - goto error; - } - - *name = g_strdup(_name); - if (!*name) { - goto error; - } - - return 0; - -error: - return -1; -} - -int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename) -{ - int ret; - Dwarf_Sword file_no; - const char *_filename = NULL; - Dwarf_Files *src_files = NULL; - Dwarf_Attribute *file_attr = NULL; - struct bt_dwarf_die *cu_die = NULL; - - if (!die || !filename) { - goto error; - } - - file_attr = g_new0(Dwarf_Attribute, 1); - if (!file_attr) { - goto error; - } - - file_attr = dwarf_attr(die->dwarf_die, DW_AT_call_file, file_attr); - if (!file_attr) { - goto error; - } - - ret = dwarf_formsdata(file_attr, &file_no); - if (ret) { - goto error; - } - - cu_die = bt_dwarf_die_create(die->cu); - if (!cu_die) { - goto error; - } - - ret = dwarf_getsrcfiles(cu_die->dwarf_die, &src_files, NULL); - if (ret) { - goto error; - } - - _filename = dwarf_filesrc(src_files, file_no, NULL, NULL); - if (!_filename) { - goto error; - } - - *filename = g_strdup(_filename); - - bt_dwarf_die_destroy(cu_die); - g_free(file_attr); - - return 0; - -error: - bt_dwarf_die_destroy(cu_die); - g_free(file_attr); - - return -1; -} - -int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die, - uint64_t *line_no) -{ - int ret = 0; - Dwarf_Attribute *line_attr = NULL; - uint64_t _line_no; - - if (!die || !line_no) { - goto error; - } - - line_attr = g_new0(Dwarf_Attribute, 1); - if (!line_attr) { - goto error; - } - - line_attr = dwarf_attr(die->dwarf_die, DW_AT_call_line, line_attr); - if (!line_attr) { - goto error; - } - - ret = dwarf_formudata(line_attr, &_line_no); - if (ret) { - goto error; - } - - *line_no = _line_no; - g_free(line_attr); - - return 0; - -error: - g_free(line_attr); - - return -1; -} - -int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, - bool *contains) -{ - int ret; - - ret = dwarf_haspc(die->dwarf_die, addr); - if (ret == -1) { - goto error; - } - - *contains = (ret == 1); - - return 0; - -error: - return -1; -} diff --git a/src/plugins/lttng-utils/debug-info/dwarf.cpp b/src/plugins/lttng-utils/debug-info/dwarf.cpp new file mode 100644 index 00000000..be5dfdec --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/dwarf.cpp @@ -0,0 +1,347 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2015 Antoine Busque + * + * Babeltrace - DWARF Information Reader + */ + +/* clang-format off */ + +#include + +#include + +#include "dwarf.hpp" + +struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info) +{ + struct bt_dwarf_cu *cu; + + if (!dwarf_info) { + goto error; + } + + cu = g_new0(struct bt_dwarf_cu, 1); + if (!cu) { + goto error; + } + cu->dwarf_info = dwarf_info; + return cu; + +error: + return NULL; +} + +void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu) +{ + g_free(cu); +} + +int bt_dwarf_cu_next(struct bt_dwarf_cu *cu) +{ + int ret; + Dwarf_Off next_offset; + size_t cu_header_size; + + if (!cu) { + ret = -1; + goto end; + } + + ret = dwarf_nextcu(cu->dwarf_info, cu->next_offset, &next_offset, + &cu_header_size, NULL, NULL, NULL); + if (ret) { + /* ret is -1 on error, 1 if no next CU. */ + goto end; + } + + cu->offset = cu->next_offset; + cu->next_offset = next_offset; + cu->header_size = cu_header_size; + +end: + return ret; +} + +struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu) +{ + Dwarf_Die *dwarf_die = NULL; + struct bt_dwarf_die *die = NULL; + + if (!cu) { + goto error; + } + + dwarf_die = g_new0(Dwarf_Die, 1); + if (!dwarf_die) { + goto error; + } + + dwarf_die = dwarf_offdie(cu->dwarf_info, cu->offset + cu->header_size, + dwarf_die); + if (!dwarf_die) { + goto error; + } + + die = g_new0(struct bt_dwarf_die, 1); + if (!die) { + goto error; + } + + die->cu = cu; + die->dwarf_die = dwarf_die; + die->depth = 0; + + return die; + +error: + g_free(dwarf_die); + g_free(die); + return NULL; +} + +void bt_dwarf_die_destroy(struct bt_dwarf_die *die) +{ + if (!die) { + return; + } + + g_free(die->dwarf_die); + g_free(die); +} + +int bt_dwarf_die_has_children(struct bt_dwarf_die *die) +{ + return dwarf_haschildren(die->dwarf_die); +} + +int bt_dwarf_die_child(struct bt_dwarf_die *die) +{ + int ret; + Dwarf_Die *child_die = NULL; + + if (!die) { + ret = -1; + goto error; + } + + child_die = g_new0(Dwarf_Die, 1); + if (!child_die) { + ret = -1; + goto error; + } + + ret = dwarf_child(die->dwarf_die, child_die); + if (ret) { + /* ret is -1 on error, 1 if no child DIE. */ + goto error; + } + + g_free(die->dwarf_die); + die->dwarf_die = child_die; + die->depth++; + return 0; + +error: + g_free(child_die); + return ret; +} + +int bt_dwarf_die_next(struct bt_dwarf_die *die) +{ + int ret; + Dwarf_Die *next_die = NULL; + + if (!die) { + ret = -1; + goto error; + } + + next_die = g_new0(Dwarf_Die, 1); + if (!next_die) { + ret = -1; + goto error; + } + + if (die->depth == 0) { + ret = dwarf_child(die->dwarf_die, next_die); + if (ret) { + /* ret is -1 on error, 1 if no child DIE. */ + goto error; + } + + die->depth = 1; + } else { + ret = dwarf_siblingof(die->dwarf_die, next_die); + if (ret) { + /* ret is -1 on error, 1 if we reached end of + * DIEs at this depth. */ + goto error; + } + } + + g_free(die->dwarf_die); + die->dwarf_die = next_die; + return 0; + +error: + g_free(next_die); + return ret; +} + +int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag) +{ + int _tag; + + if (!die || !tag) { + goto error; + } + + _tag = dwarf_tag(die->dwarf_die); + if (_tag == DW_TAG_invalid) { + goto error; + } + + *tag = _tag; + return 0; + +error: + return -1; +} + +int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name) +{ + const char *_name; + + if (!die || !name) { + goto error; + } + + _name = dwarf_diename(die->dwarf_die); + if (!_name) { + goto error; + } + + *name = g_strdup(_name); + if (!*name) { + goto error; + } + + return 0; + +error: + return -1; +} + +int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename) +{ + int ret; + Dwarf_Sword file_no; + const char *_filename = NULL; + Dwarf_Files *src_files = NULL; + Dwarf_Attribute *file_attr = NULL; + struct bt_dwarf_die *cu_die = NULL; + + if (!die || !filename) { + goto error; + } + + file_attr = g_new0(Dwarf_Attribute, 1); + if (!file_attr) { + goto error; + } + + file_attr = dwarf_attr(die->dwarf_die, DW_AT_call_file, file_attr); + if (!file_attr) { + goto error; + } + + ret = dwarf_formsdata(file_attr, &file_no); + if (ret) { + goto error; + } + + cu_die = bt_dwarf_die_create(die->cu); + if (!cu_die) { + goto error; + } + + ret = dwarf_getsrcfiles(cu_die->dwarf_die, &src_files, NULL); + if (ret) { + goto error; + } + + _filename = dwarf_filesrc(src_files, file_no, NULL, NULL); + if (!_filename) { + goto error; + } + + *filename = g_strdup(_filename); + + bt_dwarf_die_destroy(cu_die); + g_free(file_attr); + + return 0; + +error: + bt_dwarf_die_destroy(cu_die); + g_free(file_attr); + + return -1; +} + +int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die, + uint64_t *line_no) +{ + int ret = 0; + Dwarf_Attribute *line_attr = NULL; + uint64_t _line_no; + + if (!die || !line_no) { + goto error; + } + + line_attr = g_new0(Dwarf_Attribute, 1); + if (!line_attr) { + goto error; + } + + line_attr = dwarf_attr(die->dwarf_die, DW_AT_call_line, line_attr); + if (!line_attr) { + goto error; + } + + ret = dwarf_formudata(line_attr, &_line_no); + if (ret) { + goto error; + } + + *line_no = _line_no; + g_free(line_attr); + + return 0; + +error: + g_free(line_attr); + + return -1; +} + +int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, + bool *contains) +{ + int ret; + + ret = dwarf_haspc(die->dwarf_die, addr); + if (ret == -1) { + goto error; + } + + *contains = (ret == 1); + + return 0; + +error: + return -1; +} diff --git a/src/plugins/lttng-utils/debug-info/dwarf.h b/src/plugins/lttng-utils/debug-info/dwarf.h deleted file mode 100644 index 288eb9c2..00000000 --- a/src/plugins/lttng-utils/debug-info/dwarf.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2015 Antoine Busque - * - * Babeltrace - DWARF Information Reader - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_H - -#include -#include -#include -#include -#include -#include "common/macros.h" - -/* - * bt_dwarf is a wrapper over libdw providing a nicer, higher-level - * interface, to access basic debug information. - */ - -/* - * This structure corresponds to a single compilation unit (CU) for a - * given set of debug information (Dwarf type). - */ -struct bt_dwarf_cu { - Dwarf *dwarf_info; - /* Offset in bytes in the DWARF file to current CU header. */ - Dwarf_Off offset; - /* Offset in bytes in the DWARF file to next CU header. */ - Dwarf_Off next_offset; - /* Size in bytes of CU header */ - size_t header_size; -}; - -/* - * This structure represents a single debug information entry (DIE), - * within a compilation unit (CU). - */ -struct bt_dwarf_die { - struct bt_dwarf_cu *cu; - Dwarf_Die *dwarf_die; - /* - * A depth of 0 represents a root DIE, located in the DWARF - * layout on the same level as its corresponding CU entry. Its - * children DIEs will have a depth of 1, and so forth. - */ - unsigned int depth; -}; - -/** - * Instantiate a structure to access compile units (CU) from a given - * `dwarf_info`. - * - * @param dwarf_info Dwarf instance - * @returns Pointer to the new bt_dwarf_cu on success, - * NULL on failure. - */ -struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info); - -/** - * Destroy the given bt_dwarf_cu instance. - * - * @param cu bt_dwarf_cu instance - */ -void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu); - -/** - * Advance the compile unit `cu` to the next one. - * - * On success, `cu`'s offset is set to that of the current compile - * unit in the executable. On failure, `cu` remains unchanged. - * - * @param cu bt_dwarf_cu instance - * @returns 0 on success, 1 if no next CU is available, - * -1 on failure - */ -int bt_dwarf_cu_next(struct bt_dwarf_cu *cu); - -/** - * Instantiate a structure to access debug information entries (DIE) - * for the given compile unit `cu`. - * - * @param cu bt_dwarf_cu instance - * @returns Pointer to the new bt_dwarf_die on success, - * NULL on failure. - */ -struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu); - -/** - * Destroy the given bt_dwarf_die instance. - * - * @param die bt_dwarf_die instance - */ -void bt_dwarf_die_destroy(struct bt_dwarf_die *die); - -/** - * Indicates if the debug information entry `die` has children DIEs. - * - * @param die bt_dwarf_die instance - * @returns 0 if the die no child, 1 otherwise - */ -int bt_dwarf_die_has_children(struct bt_dwarf_die *die); - -/** - * Advance the debug information entry `die` to its first child, if - * any. - * - * @param die bt_dwarf_die instance - * @returns 0 on success, 1 if no child DIE is available, - * -1 on failure - */ -int bt_dwarf_die_child(struct bt_dwarf_die *die); - -/** - * Advance the debug information entry `die` to the next one. - * - * The next DIE is considered to be its sibling on the same level. The - * only exception is when the depth of the given DIE is 0, i.e. a - * newly created bt_dwarf_die, in which case next returns the first - * DIE at depth 1. - * - * The reason for staying at a depth of 1 is that this is where all - * the function DIEs (those with a tag value of DW_TAG_subprogram) are - * located, from which more specific child DIEs can then be accessed - * if needed via bt_dwarf_die_child. - * - * @param die bt_dwarf_die instance - * @returns 0 on success, 1 if no other siblings are available, -1 on - * failure - */ -int bt_dwarf_die_next(struct bt_dwarf_die *die); - -/** - * Get a DIE's tag. - * - * On success, the `tag` out parameter is set to the `die`'s tag's - * value. It remains unchanged on failure. - * - * @param die bt_dwarf_die instance - * @param tag Out parameter, the DIE's tag value - * @returns 0 on success, -1 on failure. - */ -int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag); - -/** - * Get a DIE's name. - * - * On success, the `name` out parameter is set to the DIE's name. It - * remains unchanged on failure. - * - * @param die bt_dwarf_die instance - * @param name Out parameter, the DIE's name - * @returns 0 on success, -1 on failure - */ -int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name); - -/** - * Get the full path to the DIE's callsite file. - * - * Only applies to DW_TAG_inlined_subroutine entries. The out - * parameter `filename` is set on success, unchanged on failure. - * - * @param die bt_dwarf_die instance - * @param filename Out parameter, the filename for the subroutine's - * callsite - * @returns 0 on success, -1 on failure - */ -int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename); - -/** - * Get line number for the DIE's callsite. - * - * Only applies to DW_TAG_inlined_subroutine entries. The out - * parameter `line_no` is set on success, unchanged on failure. - * - * @param die bt_dwarf_die instance - * @param line_no Out parameter, the line number for the - * subroutine's callsite - * @returns 0 on success, -1 on failure - */ -int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die, - uint64_t *line_no); - -/** - * Verifies whether a given DIE contains the virtual memory address - * `addr`. - * - * On success, the out parameter `contains` is set with the boolean - * value indicating whether the DIE's range covers `addr`. On failure, - * it remains unchanged. - * - * @param die bt_dwarf_die instance - * @param addr The memory address to verify - * @param contains Out parameter, true if addr is contained, - * false if not - * @returns 0 on success, -1 on failure - */ -int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, - bool *contains); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_H */ diff --git a/src/plugins/lttng-utils/debug-info/dwarf.hpp b/src/plugins/lttng-utils/debug-info/dwarf.hpp new file mode 100644 index 00000000..3bf593bb --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/dwarf.hpp @@ -0,0 +1,206 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2015 Antoine Busque + * + * Babeltrace - DWARF Information Reader + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_HPP + +#include +#include +#include +#include +#include +#include "common/macros.h" + +/* + * bt_dwarf is a wrapper over libdw providing a nicer, higher-level + * interface, to access basic debug information. + */ + +/* + * This structure corresponds to a single compilation unit (CU) for a + * given set of debug information (Dwarf type). + */ +struct bt_dwarf_cu { + Dwarf *dwarf_info; + /* Offset in bytes in the DWARF file to current CU header. */ + Dwarf_Off offset; + /* Offset in bytes in the DWARF file to next CU header. */ + Dwarf_Off next_offset; + /* Size in bytes of CU header */ + size_t header_size; +}; + +/* + * This structure represents a single debug information entry (DIE), + * within a compilation unit (CU). + */ +struct bt_dwarf_die { + struct bt_dwarf_cu *cu; + Dwarf_Die *dwarf_die; + /* + * A depth of 0 represents a root DIE, located in the DWARF + * layout on the same level as its corresponding CU entry. Its + * children DIEs will have a depth of 1, and so forth. + */ + unsigned int depth; +}; + +/** + * Instantiate a structure to access compile units (CU) from a given + * `dwarf_info`. + * + * @param dwarf_info Dwarf instance + * @returns Pointer to the new bt_dwarf_cu on success, + * NULL on failure. + */ +struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info); + +/** + * Destroy the given bt_dwarf_cu instance. + * + * @param cu bt_dwarf_cu instance + */ +void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu); + +/** + * Advance the compile unit `cu` to the next one. + * + * On success, `cu`'s offset is set to that of the current compile + * unit in the executable. On failure, `cu` remains unchanged. + * + * @param cu bt_dwarf_cu instance + * @returns 0 on success, 1 if no next CU is available, + * -1 on failure + */ +int bt_dwarf_cu_next(struct bt_dwarf_cu *cu); + +/** + * Instantiate a structure to access debug information entries (DIE) + * for the given compile unit `cu`. + * + * @param cu bt_dwarf_cu instance + * @returns Pointer to the new bt_dwarf_die on success, + * NULL on failure. + */ +struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu); + +/** + * Destroy the given bt_dwarf_die instance. + * + * @param die bt_dwarf_die instance + */ +void bt_dwarf_die_destroy(struct bt_dwarf_die *die); + +/** + * Indicates if the debug information entry `die` has children DIEs. + * + * @param die bt_dwarf_die instance + * @returns 0 if the die no child, 1 otherwise + */ +int bt_dwarf_die_has_children(struct bt_dwarf_die *die); + +/** + * Advance the debug information entry `die` to its first child, if + * any. + * + * @param die bt_dwarf_die instance + * @returns 0 on success, 1 if no child DIE is available, + * -1 on failure + */ +int bt_dwarf_die_child(struct bt_dwarf_die *die); + +/** + * Advance the debug information entry `die` to the next one. + * + * The next DIE is considered to be its sibling on the same level. The + * only exception is when the depth of the given DIE is 0, i.e. a + * newly created bt_dwarf_die, in which case next returns the first + * DIE at depth 1. + * + * The reason for staying at a depth of 1 is that this is where all + * the function DIEs (those with a tag value of DW_TAG_subprogram) are + * located, from which more specific child DIEs can then be accessed + * if needed via bt_dwarf_die_child. + * + * @param die bt_dwarf_die instance + * @returns 0 on success, 1 if no other siblings are available, -1 on + * failure + */ +int bt_dwarf_die_next(struct bt_dwarf_die *die); + +/** + * Get a DIE's tag. + * + * On success, the `tag` out parameter is set to the `die`'s tag's + * value. It remains unchanged on failure. + * + * @param die bt_dwarf_die instance + * @param tag Out parameter, the DIE's tag value + * @returns 0 on success, -1 on failure. + */ +int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag); + +/** + * Get a DIE's name. + * + * On success, the `name` out parameter is set to the DIE's name. It + * remains unchanged on failure. + * + * @param die bt_dwarf_die instance + * @param name Out parameter, the DIE's name + * @returns 0 on success, -1 on failure + */ +int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name); + +/** + * Get the full path to the DIE's callsite file. + * + * Only applies to DW_TAG_inlined_subroutine entries. The out + * parameter `filename` is set on success, unchanged on failure. + * + * @param die bt_dwarf_die instance + * @param filename Out parameter, the filename for the subroutine's + * callsite + * @returns 0 on success, -1 on failure + */ +int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename); + +/** + * Get line number for the DIE's callsite. + * + * Only applies to DW_TAG_inlined_subroutine entries. The out + * parameter `line_no` is set on success, unchanged on failure. + * + * @param die bt_dwarf_die instance + * @param line_no Out parameter, the line number for the + * subroutine's callsite + * @returns 0 on success, -1 on failure + */ +int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die, + uint64_t *line_no); + +/** + * Verifies whether a given DIE contains the virtual memory address + * `addr`. + * + * On success, the out parameter `contains` is set with the boolean + * value indicating whether the DIE's range covers `addr`. On failure, + * it remains unchanged. + * + * @param die bt_dwarf_die instance + * @param addr The memory address to verify + * @param contains Out parameter, true if addr is contained, + * false if not + * @returns 0 on success, -1 on failure + */ +int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, + bool *contains); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_DWARF_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c deleted file mode 100644 index 51f76c00..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR data object copy - */ - -#define BT_COMP_LOG_SELF_COMP self_comp -#define BT_LOG_OUTPUT_LEVEL log_level -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-DATA-COPY" -#include "logging/comp-logging.h" - -#include -#include - -#include "common/assert.h" -#include "common/common.h" - -#include "trace-ir-data-copy.h" - -enum debug_info_trace_ir_mapping_status copy_trace_content( - const bt_trace *in_trace, bt_trace *out_trace, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - const char *trace_name; - uint64_t i, env_field_count; - - BT_COMP_LOGD("Copying content of trace: in-t-addr=%p, out-t-addr=%p", - in_trace, out_trace); - - trace_name = bt_trace_get_name(in_trace); - - /* Copy the trace name. */ - if (trace_name) { - bt_trace_set_name_status set_name_status = - bt_trace_set_name(out_trace, trace_name); - if (set_name_status != BT_TRACE_SET_NAME_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set trace's name: " - "out-t-addr=%p, name=\"%s\"", out_trace, - trace_name); - status = (int) set_name_status; - goto end; - } - } - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_trace_set_user_attributes(out_trace, - bt_trace_borrow_user_attributes_const(in_trace)); - - /* - * Do not copy the trace UUID as the trace may be modified and should - * no longer have the same UUID. - */ - - /* - * Go over all the entries in the environment section of the - * trace and copy the content to the new trace. - */ - env_field_count = bt_trace_get_environment_entry_count(in_trace); - for (i = 0; i < env_field_count; i++) { - const char *value_name; - const bt_value *value = NULL; - bt_trace_set_environment_entry_status set_env_status; - - bt_trace_borrow_environment_entry_by_index_const( - in_trace, i, &value_name, &value); - - BT_COMP_LOGD("Copying trace environment entry: " - "index=%" PRId64 ", value-addr=%p, value-name=\"%s\"", - i, value, value_name); - - BT_ASSERT(value_name); - BT_ASSERT(value); - - if (bt_value_is_signed_integer(value)) { - set_env_status = bt_trace_set_environment_entry_integer( - out_trace, value_name, - bt_value_integer_signed_get( value)); - } else if (bt_value_is_string(value)) { - set_env_status = bt_trace_set_environment_entry_string( - out_trace, value_name, - bt_value_string_get(value)); - } else { - bt_common_abort(); - } - - if (set_env_status != BT_TRACE_SET_ENVIRONMENT_ENTRY_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy trace's environment: " - "out-t-addr=%p, name=\"%s\"", - out_trace, trace_name); - status = (int) set_env_status; - goto end; - } - } - - BT_COMP_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p", - in_trace, out_trace); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status copy_stream_content( - const bt_stream *in_stream, bt_stream *out_stream, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - const char *stream_name; - - BT_COMP_LOGD("Copying content of stream: in-s-addr=%p, out-s-addr=%p", - in_stream, out_stream); - - stream_name = bt_stream_get_name(in_stream); - - if (stream_name) { - bt_stream_set_name_status set_name_status = - bt_stream_set_name(out_stream, stream_name); - if (set_name_status != BT_STREAM_SET_NAME_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set stream's name: " - "stream-addr=%p, name=\"%s\"", out_stream, - stream_name); - status = (int) set_name_status; - goto end; - } - } - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_stream_set_user_attributes(out_stream, - bt_stream_borrow_user_attributes_const(in_stream)); - - BT_COMP_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p", - in_stream, out_stream); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status copy_packet_content( - const bt_packet *in_packet, bt_packet *out_packet, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - const bt_field *in_context_field; - bt_field *out_context_field; - - BT_COMP_LOGD("Copying content of packet: in-p-addr=%p, out-p-addr=%p", - in_packet, out_packet); - - /* Copy context field. */ - in_context_field = bt_packet_borrow_context_field_const(in_packet); - if (in_context_field) { - out_context_field = bt_packet_borrow_context_field(out_packet); - BT_ASSERT(out_context_field); - status = copy_field_content(in_context_field, out_context_field, - log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy context field: " - "in-ctx-f-addr=%p, out-ctx-f-addr=%p", - in_context_field, out_context_field); - goto end; - } - } - - BT_COMP_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p", - in_packet, out_packet); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status copy_event_content( - const bt_event *in_event, bt_event *out_event, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - const bt_field *in_common_ctx_field, *in_specific_ctx_field, - *in_payload_field; - bt_field *out_common_ctx_field, *out_specific_ctx_field, - *out_payload_field; - - BT_COMP_LOGD("Copying content of event: in-e-addr=%p, out-e-addr=%p", - in_event, out_event); - in_common_ctx_field = - bt_event_borrow_common_context_field_const(in_event); - if (in_common_ctx_field) { - out_common_ctx_field = - bt_event_borrow_common_context_field(out_event); - BT_ASSERT_DBG(out_common_ctx_field); - - status = copy_field_content(in_common_ctx_field, - out_common_ctx_field, log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy common context field: " - "in-comm-ctx-f-addr=%p, out-comm-ctx-f-addr=%p", - in_common_ctx_field, out_common_ctx_field); - goto end; - } - } - - in_specific_ctx_field = - bt_event_borrow_specific_context_field_const(in_event); - if (in_specific_ctx_field) { - out_specific_ctx_field = - bt_event_borrow_specific_context_field(out_event); - BT_ASSERT_DBG(out_specific_ctx_field); - - status = copy_field_content(in_specific_ctx_field, - out_specific_ctx_field, log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy specific context field: " - "in-spec-ctx-f-addr=%p, out-spec-ctx-f-addr=%p", - in_specific_ctx_field, out_specific_ctx_field); - goto end; - } - } - - in_payload_field = bt_event_borrow_payload_field_const(in_event); - if (in_payload_field) { - out_payload_field = bt_event_borrow_payload_field(out_event); - BT_ASSERT_DBG(out_payload_field); - - status = copy_field_content(in_payload_field, - out_payload_field, log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy payloat field: " - "in-payload-f-addr=%p, out-payload-f-addr=%p", - in_payload_field, out_payload_field); - goto end; - } - } - - BT_COMP_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p", - in_event, out_event); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status copy_field_content( - const bt_field *in_field, bt_field *out_field, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - bt_field_class_type in_fc_type, out_fc_type; - - in_fc_type = bt_field_get_class_type(in_field); - out_fc_type = bt_field_get_class_type(out_field); - BT_ASSERT_DBG(in_fc_type == out_fc_type); - - BT_COMP_LOGT("Copying content of field: in-f-addr=%p, out-f-addr=%p", - in_field, out_field); - - if (in_fc_type == BT_FIELD_CLASS_TYPE_BOOL) { - bt_field_bool_set_value(out_field, - bt_field_bool_get_value(in_field)); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) { - bt_field_bit_array_set_value_as_integer(out_field, - bt_field_bit_array_get_value_as_integer(in_field)); - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) { - bt_field_integer_unsigned_set_value(out_field, - bt_field_integer_unsigned_get_value(in_field)); - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)) { - bt_field_integer_signed_set_value(out_field, - bt_field_integer_signed_get_value(in_field)); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { - bt_field_real_single_precision_set_value(out_field, - bt_field_real_single_precision_get_value(in_field)); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) { - bt_field_real_double_precision_set_value(out_field, - bt_field_real_double_precision_get_value(in_field)); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRING) { - const char *str = bt_field_string_get_value(in_field); - bt_field_string_set_value_status set_value_status = - bt_field_string_set_value(out_field, str); - if (set_value_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set string field's value: " - "out-str-f-addr=%p, str=\"%s\"" PRId64, - out_field, str); - status = (int) set_value_status; - goto end; - } - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { - uint64_t i, nb_member_struct; - const bt_field *in_member_field; - bt_field *out_member_field; - const bt_field_class *in_field_class; - const char *in_member_name; - - in_field_class = bt_field_borrow_class_const(in_field); - nb_member_struct = bt_field_class_structure_get_member_count( - in_field_class); - - /* - * Iterate over the fields by names in the input field to avoid - * problem if the struct fields are not in the same order after - * the debug-info was added. - */ - for (i = 0; i < nb_member_struct; i++) { - const bt_field_class_structure_member *member = - bt_field_class_structure_borrow_member_by_index_const( - in_field_class, i); - - in_member_name = - bt_field_class_structure_member_get_name( - member); - in_member_field = - bt_field_structure_borrow_member_field_by_name_const( - in_field, in_member_name); - out_member_field = - bt_field_structure_borrow_member_field_by_name( - out_field, in_member_name); - - status = copy_field_content(in_member_field, - out_member_field, log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy struct member field: " - "out-struct-f-addr=%p, " - "out-struct-member-f-addr=%p, " - "member-name=\"%s\"", - out_field, out_member_field, - in_member_name); - goto end; - } - } - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_ARRAY)) { - const bt_field *in_element_field; - bt_field *out_element_field; - uint64_t i, array_len; - bt_field_array_dynamic_set_length_status set_len_status; - - array_len = bt_field_array_get_length(in_field); - - if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { - set_len_status = bt_field_array_dynamic_set_length( - out_field, array_len); - if (set_len_status != - BT_FIELD_DYNAMIC_ARRAY_SET_LENGTH_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot set dynamic array field's length field: " - "out-arr-f-addr=%p, arr-length=%" PRIu64, - out_field, array_len); - status = (int) set_len_status; - goto end; - } - } - - for (i = 0; i < array_len; i++) { - in_element_field = - bt_field_array_borrow_element_field_by_index_const( - in_field, i); - out_element_field = - bt_field_array_borrow_element_field_by_index( - out_field, i); - status = copy_field_content(in_element_field, - out_element_field, log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy element field: " - "out-arr-f-addr=%p, out-arr-elem-f-addr=%p", - out_field, out_element_field); - goto end; - } - } - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_OPTION)) { - const bt_field *in_option_field; - bt_field *out_option_field; - - in_option_field = bt_field_option_borrow_field_const(in_field); - - if (in_option_field) { - bt_field_option_set_has_field(out_field, BT_TRUE); - out_option_field = bt_field_option_borrow_field( - out_field); - BT_ASSERT_DBG(out_option_field); - status = copy_field_content(in_option_field, out_option_field, - log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy option field: " - "out-opt-f-addr=%p, out-opt-field-f-addr=%p", - out_field, out_option_field); - goto end; - } - } else { - bt_field_option_set_has_field(out_field, BT_FALSE); - } - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_VARIANT)) { - bt_field_variant_select_option_by_index_status sel_opt_status; - uint64_t in_selected_option_idx; - const bt_field *in_option_field; - bt_field *out_option_field; - - in_selected_option_idx = - bt_field_variant_get_selected_option_index( - in_field); - sel_opt_status = bt_field_variant_select_option_by_index(out_field, - in_selected_option_idx); - if (sel_opt_status != - BT_FIELD_VARIANT_SELECT_OPTION_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot select variant field's option field: " - "out-var-f-addr=%p, opt-index=%" PRId64, - out_field, in_selected_option_idx); - status = (int) sel_opt_status; - goto end; - } - - in_option_field = bt_field_variant_borrow_selected_option_field_const(in_field); - out_option_field = bt_field_variant_borrow_selected_option_field(out_field); - - status = copy_field_content(in_option_field, out_option_field, - log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy element field: " - "out-var-f-addr=%p, out-opt-f-addr=%p", - out_field, out_option_field); - goto end; - } - } else { - bt_common_abort(); - } - - BT_COMP_LOGT("Copied content of field: in-f-addr=%p, out-f-addr=%p", - in_field, out_field); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.cpp b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.cpp new file mode 100644 index 00000000..810e84d0 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.cpp @@ -0,0 +1,449 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR data object copy + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP self_comp +#define BT_LOG_OUTPUT_LEVEL log_level +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-DATA-COPY" +#include "logging/comp-logging.h" + +#include +#include + +#include "common/assert.h" +#include "common/common.h" + +#include "trace-ir-data-copy.hpp" + +enum debug_info_trace_ir_mapping_status copy_trace_content( + const bt_trace *in_trace, bt_trace *out_trace, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + const char *trace_name; + uint64_t i, env_field_count; + + BT_COMP_LOGD("Copying content of trace: in-t-addr=%p, out-t-addr=%p", + in_trace, out_trace); + + trace_name = bt_trace_get_name(in_trace); + + /* Copy the trace name. */ + if (trace_name) { + bt_trace_set_name_status set_name_status = + bt_trace_set_name(out_trace, trace_name); + if (set_name_status != BT_TRACE_SET_NAME_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set trace's name: " + "out-t-addr=%p, name=\"%s\"", out_trace, + trace_name); + status = static_cast(set_name_status); + goto end; + } + } + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_trace_set_user_attributes(out_trace, + bt_trace_borrow_user_attributes_const(in_trace)); + + /* + * Do not copy the trace UUID as the trace may be modified and should + * no longer have the same UUID. + */ + + /* + * Go over all the entries in the environment section of the + * trace and copy the content to the new trace. + */ + env_field_count = bt_trace_get_environment_entry_count(in_trace); + for (i = 0; i < env_field_count; i++) { + const char *value_name; + const bt_value *value = NULL; + bt_trace_set_environment_entry_status set_env_status; + + bt_trace_borrow_environment_entry_by_index_const( + in_trace, i, &value_name, &value); + + BT_COMP_LOGD("Copying trace environment entry: " + "index=%" PRId64 ", value-addr=%p, value-name=\"%s\"", + i, value, value_name); + + BT_ASSERT(value_name); + BT_ASSERT(value); + + if (bt_value_is_signed_integer(value)) { + set_env_status = bt_trace_set_environment_entry_integer( + out_trace, value_name, + bt_value_integer_signed_get( value)); + } else if (bt_value_is_string(value)) { + set_env_status = bt_trace_set_environment_entry_string( + out_trace, value_name, + bt_value_string_get(value)); + } else { + bt_common_abort(); + } + + if (set_env_status != BT_TRACE_SET_ENVIRONMENT_ENTRY_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy trace's environment: " + "out-t-addr=%p, name=\"%s\"", + out_trace, trace_name); + status = static_cast(set_env_status); + goto end; + } + } + + BT_COMP_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p", + in_trace, out_trace); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status copy_stream_content( + const bt_stream *in_stream, bt_stream *out_stream, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + const char *stream_name; + + BT_COMP_LOGD("Copying content of stream: in-s-addr=%p, out-s-addr=%p", + in_stream, out_stream); + + stream_name = bt_stream_get_name(in_stream); + + if (stream_name) { + bt_stream_set_name_status set_name_status = + bt_stream_set_name(out_stream, stream_name); + if (set_name_status != BT_STREAM_SET_NAME_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set stream's name: " + "stream-addr=%p, name=\"%s\"", out_stream, + stream_name); + status = static_cast(set_name_status); + goto end; + } + } + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_stream_set_user_attributes(out_stream, + bt_stream_borrow_user_attributes_const(in_stream)); + + BT_COMP_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p", + in_stream, out_stream); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status copy_packet_content( + const bt_packet *in_packet, bt_packet *out_packet, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + const bt_field *in_context_field; + bt_field *out_context_field; + + BT_COMP_LOGD("Copying content of packet: in-p-addr=%p, out-p-addr=%p", + in_packet, out_packet); + + /* Copy context field. */ + in_context_field = bt_packet_borrow_context_field_const(in_packet); + if (in_context_field) { + out_context_field = bt_packet_borrow_context_field(out_packet); + BT_ASSERT(out_context_field); + status = copy_field_content(in_context_field, out_context_field, + log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy context field: " + "in-ctx-f-addr=%p, out-ctx-f-addr=%p", + in_context_field, out_context_field); + goto end; + } + } + + BT_COMP_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p", + in_packet, out_packet); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status copy_event_content( + const bt_event *in_event, bt_event *out_event, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + const bt_field *in_common_ctx_field, *in_specific_ctx_field, + *in_payload_field; + bt_field *out_common_ctx_field, *out_specific_ctx_field, + *out_payload_field; + + BT_COMP_LOGD("Copying content of event: in-e-addr=%p, out-e-addr=%p", + in_event, out_event); + in_common_ctx_field = + bt_event_borrow_common_context_field_const(in_event); + if (in_common_ctx_field) { + out_common_ctx_field = + bt_event_borrow_common_context_field(out_event); + BT_ASSERT_DBG(out_common_ctx_field); + + status = copy_field_content(in_common_ctx_field, + out_common_ctx_field, log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy common context field: " + "in-comm-ctx-f-addr=%p, out-comm-ctx-f-addr=%p", + in_common_ctx_field, out_common_ctx_field); + goto end; + } + } + + in_specific_ctx_field = + bt_event_borrow_specific_context_field_const(in_event); + if (in_specific_ctx_field) { + out_specific_ctx_field = + bt_event_borrow_specific_context_field(out_event); + BT_ASSERT_DBG(out_specific_ctx_field); + + status = copy_field_content(in_specific_ctx_field, + out_specific_ctx_field, log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy specific context field: " + "in-spec-ctx-f-addr=%p, out-spec-ctx-f-addr=%p", + in_specific_ctx_field, out_specific_ctx_field); + goto end; + } + } + + in_payload_field = bt_event_borrow_payload_field_const(in_event); + if (in_payload_field) { + out_payload_field = bt_event_borrow_payload_field(out_event); + BT_ASSERT_DBG(out_payload_field); + + status = copy_field_content(in_payload_field, + out_payload_field, log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy payloat field: " + "in-payload-f-addr=%p, out-payload-f-addr=%p", + in_payload_field, out_payload_field); + goto end; + } + } + + BT_COMP_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p", + in_event, out_event); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status copy_field_content( + const bt_field *in_field, bt_field *out_field, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + bt_field_class_type in_fc_type, out_fc_type; + + in_fc_type = bt_field_get_class_type(in_field); + out_fc_type = bt_field_get_class_type(out_field); + BT_ASSERT_DBG(in_fc_type == out_fc_type); + + BT_COMP_LOGT("Copying content of field: in-f-addr=%p, out-f-addr=%p", + in_field, out_field); + + if (in_fc_type == BT_FIELD_CLASS_TYPE_BOOL) { + bt_field_bool_set_value(out_field, + bt_field_bool_get_value(in_field)); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) { + bt_field_bit_array_set_value_as_integer(out_field, + bt_field_bit_array_get_value_as_integer(in_field)); + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) { + bt_field_integer_unsigned_set_value(out_field, + bt_field_integer_unsigned_get_value(in_field)); + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)) { + bt_field_integer_signed_set_value(out_field, + bt_field_integer_signed_get_value(in_field)); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { + bt_field_real_single_precision_set_value(out_field, + bt_field_real_single_precision_get_value(in_field)); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) { + bt_field_real_double_precision_set_value(out_field, + bt_field_real_double_precision_get_value(in_field)); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRING) { + const char *str = bt_field_string_get_value(in_field); + bt_field_string_set_value_status set_value_status = + bt_field_string_set_value(out_field, str); + if (set_value_status != BT_FIELD_STRING_SET_VALUE_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot set string field's value: " + "out-str-f-addr=%p, str=\"%s\"" PRId64, + out_field, str); + status = static_cast(set_value_status); + goto end; + } + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { + uint64_t i, nb_member_struct; + const bt_field *in_member_field; + bt_field *out_member_field; + const bt_field_class *in_field_class; + const char *in_member_name; + + in_field_class = bt_field_borrow_class_const(in_field); + nb_member_struct = bt_field_class_structure_get_member_count( + in_field_class); + + /* + * Iterate over the fields by names in the input field to avoid + * problem if the struct fields are not in the same order after + * the debug-info was added. + */ + for (i = 0; i < nb_member_struct; i++) { + const bt_field_class_structure_member *member = + bt_field_class_structure_borrow_member_by_index_const( + in_field_class, i); + + in_member_name = + bt_field_class_structure_member_get_name( + member); + in_member_field = + bt_field_structure_borrow_member_field_by_name_const( + in_field, in_member_name); + out_member_field = + bt_field_structure_borrow_member_field_by_name( + out_field, in_member_name); + + status = copy_field_content(in_member_field, + out_member_field, log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy struct member field: " + "out-struct-f-addr=%p, " + "out-struct-member-f-addr=%p, " + "member-name=\"%s\"", + out_field, out_member_field, + in_member_name); + goto end; + } + } + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_ARRAY)) { + const bt_field *in_element_field; + bt_field *out_element_field; + uint64_t i, array_len; + bt_field_array_dynamic_set_length_status set_len_status; + + array_len = bt_field_array_get_length(in_field); + + if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { + set_len_status = bt_field_array_dynamic_set_length( + out_field, array_len); + if (set_len_status != + BT_FIELD_DYNAMIC_ARRAY_SET_LENGTH_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot set dynamic array field's length field: " + "out-arr-f-addr=%p, arr-length=%" PRIu64, + out_field, array_len); + status = static_cast(set_len_status); + goto end; + } + } + + for (i = 0; i < array_len; i++) { + in_element_field = + bt_field_array_borrow_element_field_by_index_const( + in_field, i); + out_element_field = + bt_field_array_borrow_element_field_by_index( + out_field, i); + status = copy_field_content(in_element_field, + out_element_field, log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy element field: " + "out-arr-f-addr=%p, out-arr-elem-f-addr=%p", + out_field, out_element_field); + goto end; + } + } + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_OPTION)) { + const bt_field *in_option_field; + bt_field *out_option_field; + + in_option_field = bt_field_option_borrow_field_const(in_field); + + if (in_option_field) { + bt_field_option_set_has_field(out_field, BT_TRUE); + out_option_field = bt_field_option_borrow_field( + out_field); + BT_ASSERT_DBG(out_option_field); + status = copy_field_content(in_option_field, out_option_field, + log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy option field: " + "out-opt-f-addr=%p, out-opt-field-f-addr=%p", + out_field, out_option_field); + goto end; + } + } else { + bt_field_option_set_has_field(out_field, BT_FALSE); + } + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_VARIANT)) { + bt_field_variant_select_option_by_index_status sel_opt_status; + uint64_t in_selected_option_idx; + const bt_field *in_option_field; + bt_field *out_option_field; + + in_selected_option_idx = + bt_field_variant_get_selected_option_index( + in_field); + sel_opt_status = bt_field_variant_select_option_by_index(out_field, + in_selected_option_idx); + if (sel_opt_status != + BT_FIELD_VARIANT_SELECT_OPTION_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot select variant field's option field: " + "out-var-f-addr=%p, opt-index=%" PRId64, + out_field, in_selected_option_idx); + status = static_cast(sel_opt_status); + goto end; + } + + in_option_field = bt_field_variant_borrow_selected_option_field_const(in_field); + out_option_field = bt_field_variant_borrow_selected_option_field(out_field); + + status = copy_field_content(in_option_field, out_option_field, + log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy element field: " + "out-var-f-addr=%p, out-opt-f-addr=%p", + out_field, out_option_field); + goto end; + } + } else { + bt_common_abort(); + } + + BT_COMP_LOGT("Copied content of field: in-f-addr=%p, out-f-addr=%p", + in_field, out_field); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h deleted file mode 100644 index 847befa1..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR data object copy - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_H - -#include - -#include "common/macros.h" -#include "trace-ir-mapping.h" - -enum debug_info_trace_ir_mapping_status copy_trace_content( - const bt_trace *in_trace, bt_trace *out_trace, - bt_logging_level log_level, bt_self_component *self_comp); -enum debug_info_trace_ir_mapping_status copy_stream_content( - const bt_stream *in_stream, bt_stream *out_stream, - bt_logging_level log_level, bt_self_component *self_comp); -enum debug_info_trace_ir_mapping_status copy_packet_content( - const bt_packet *in_packet, bt_packet *out_packet, - bt_logging_level log_level, bt_self_component *self_comp); -enum debug_info_trace_ir_mapping_status copy_event_content( - const bt_event *in_event, bt_event *out_event, - bt_logging_level log_level, bt_self_component *self_comp); -enum debug_info_trace_ir_mapping_status copy_field_content( - const bt_field *in_field, bt_field *out_field, - bt_logging_level log_level, bt_self_component *self_comp); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_H */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.hpp b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.hpp new file mode 100644 index 00000000..f00c19f5 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.hpp @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR data object copy + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_HPP + +#include + +#include "common/macros.h" +#include "trace-ir-mapping.hpp" + +enum debug_info_trace_ir_mapping_status copy_trace_content( + const bt_trace *in_trace, bt_trace *out_trace, + bt_logging_level log_level, bt_self_component *self_comp); +enum debug_info_trace_ir_mapping_status copy_stream_content( + const bt_stream *in_stream, bt_stream *out_stream, + bt_logging_level log_level, bt_self_component *self_comp); +enum debug_info_trace_ir_mapping_status copy_packet_content( + const bt_packet *in_packet, bt_packet *out_packet, + bt_logging_level log_level, bt_self_component *self_comp); +enum debug_info_trace_ir_mapping_status copy_event_content( + const bt_event *in_event, bt_event *out_event, + bt_logging_level log_level, bt_self_component *self_comp); +enum debug_info_trace_ir_mapping_status copy_field_content( + const bt_field *in_field, bt_field *out_field, + bt_logging_level log_level, bt_self_component *self_comp); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_DATA_COPY_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.c b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.c deleted file mode 100644 index 5c805f2d..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Mapping of IR metadata and data object between input and output - * trace - */ - -#define BT_COMP_LOG_SELF_COMP (ir_maps->self_comp) -#define BT_LOG_OUTPUT_LEVEL (ir_maps->log_level) -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-MAPPING" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include - -#include "debug-info.h" -#include "trace-ir-data-copy.h" -#include "trace-ir-mapping.h" -#include "trace-ir-metadata-copy.h" - -static -bt_trace_class *create_new_mapped_trace_class(struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *metadata_maps; - - BT_COMP_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class); - - BT_ASSERT(ir_maps); - BT_ASSERT(in_trace_class); - - metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, - in_trace_class); - - BT_ASSERT(!metadata_maps->output_trace_class); - - /* Create the output trace class. */ - metadata_maps->output_trace_class = - bt_trace_class_create(ir_maps->self_comp); - if (!metadata_maps->output_trace_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error create output trace class"); - goto error; - } - - /* Copy the content over and add to the mapping. */ - status = copy_trace_class_content(ir_maps, in_trace_class, - metadata_maps->output_trace_class, ir_maps->log_level, - ir_maps->self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output trace class" - "in-tc-addr=%p, out-tc-addr=%p", in_trace_class, - metadata_maps->output_trace_class); - goto error; - } - - BT_COMP_LOGD("Created new mapped trace class: " - "in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, metadata_maps->output_trace_class); - - goto end; -error: - BT_TRACE_CLASS_PUT_REF_AND_RESET(metadata_maps->output_trace_class); -end: - return metadata_maps->output_trace_class; -} - -static -bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps, - const bt_trace *in_trace) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *metadata_maps; - const bt_trace_class *in_trace_class; - bt_trace *out_trace; - - BT_COMP_LOGD("Creating new mapped trace: in-t-addr=%p", in_trace); - BT_ASSERT(ir_maps); - BT_ASSERT(in_trace); - - in_trace_class = bt_trace_borrow_class_const(in_trace); - metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, - in_trace_class); - - if (!metadata_maps->output_trace_class) { - /* - * If there is no output trace class yet, create a one and add - * it to the mapping. - */ - metadata_maps->output_trace_class = - create_new_mapped_trace_class(ir_maps, in_trace_class); - if (!metadata_maps->output_trace_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error create output trace class"); - out_trace = NULL; - goto end; - } - } - - /* Create the output trace from the output trace class. */ - out_trace = bt_trace_create(metadata_maps->output_trace_class); - if (!out_trace) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error create output trace"); - goto end; - } - - /* Copy the content over to the output trace. */ - status = copy_trace_content(in_trace, out_trace, ir_maps->log_level, - ir_maps->self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output trace" - "in-t-addr=%p, out-t-addr=%p", in_trace, out_trace); - goto error; - } - - BT_COMP_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p", - in_trace, out_trace); - goto end; - -error: - BT_TRACE_PUT_REF_AND_RESET(out_trace); -end: - return out_trace; -} - -bt_stream_class *trace_ir_mapping_borrow_mapped_stream_class( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class) -{ - BT_ASSERT_DBG(ir_maps); - BT_ASSERT_DBG(in_stream_class); - - struct trace_ir_metadata_maps *md_maps = - borrow_metadata_maps_from_input_stream_class(ir_maps, - in_stream_class); - return g_hash_table_lookup(md_maps->stream_class_map, - (gpointer) in_stream_class); -} - -bt_stream_class *trace_ir_mapping_create_new_mapped_stream_class( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *md_maps; - bt_stream_class *out_stream_class; - - BT_COMP_LOGD("Creating new mapped stream class: in-sc-addr=%p", - in_stream_class); - - BT_ASSERT(ir_maps); - BT_ASSERT(in_stream_class); - BT_ASSERT(!trace_ir_mapping_borrow_mapped_stream_class(ir_maps, - in_stream_class)); - - md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, - in_stream_class); - - BT_ASSERT(md_maps); - - /* Create the output stream class. */ - out_stream_class = bt_stream_class_create_with_id( - md_maps->output_trace_class, - bt_stream_class_get_id(in_stream_class)); - if (!out_stream_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error create output stream class"); - goto end; - } - - /* Add it to the mapping. The mapping now owns out_stream_class. */ - g_hash_table_insert(md_maps->stream_class_map, - (gpointer) in_stream_class, out_stream_class); - - /* Copy the content over to the output stream class. */ - status = copy_stream_class_content(ir_maps, in_stream_class, - out_stream_class); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output stream class: " - "in-sc-addr=%p, out-sc-addr=%p", in_stream_class, - out_stream_class); - goto error; - } - - BT_COMP_LOGD("Created new mapped stream class: " - "in-sc-addr=%p, out-sc-addr=%p", - in_stream_class, out_stream_class); - - goto end; -error: - out_stream_class = NULL; -end: - return out_stream_class; -} - -static -bt_stream *borrow_mapped_stream(struct trace_ir_data_maps *d_maps, - const bt_stream *in_stream) -{ - BT_ASSERT_DBG(d_maps); - BT_ASSERT_DBG(in_stream); - - return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream); -} - -bt_stream *trace_ir_mapping_create_new_mapped_stream( - struct trace_ir_maps *ir_maps, const bt_stream *in_stream) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_data_maps *d_maps; - const bt_stream_class *in_stream_class; - const bt_trace *in_trace; - bt_stream_class *out_stream_class; - bt_stream *out_stream = NULL; - - BT_ASSERT(ir_maps); - BT_ASSERT(in_stream); - BT_COMP_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream); - - in_trace = bt_stream_borrow_trace_const(in_stream); - - d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace); - if (!d_maps->output_trace) { - /* Create the output trace for this input trace. */ - d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace); - if (!d_maps->output_trace) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating mapped trace"); - goto error; - } - } - - BT_ASSERT(d_maps->output_trace); - BT_ASSERT(!borrow_mapped_stream(d_maps, in_stream)); - - in_stream_class = bt_stream_borrow_class_const(in_stream); - out_stream_class = trace_ir_mapping_borrow_mapped_stream_class(ir_maps, - in_stream_class); - - if (!out_stream_class) { - /* Create the output stream class for this input stream class. */ - out_stream_class = trace_ir_mapping_create_new_mapped_stream_class( - ir_maps, in_stream_class); - if (!out_stream_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating mapped stream class"); - goto error; - } - } - BT_ASSERT(out_stream_class); - - /* Create the output stream for this input stream. */ - out_stream = bt_stream_create_with_id(out_stream_class, - d_maps->output_trace, bt_stream_get_id(in_stream)); - if (!out_stream) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output stream"); - goto error; - } - - /* Add it to the mapping. The mapping now owns out_stream.*/ - g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream, - out_stream); - - /* Copy the content over to the output stream. */ - status = copy_stream_content(in_stream, out_stream, ir_maps->log_level, - ir_maps->self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output stream: " - "in-s-addr=%p, out-s-addr=%p", in_stream, out_stream); - goto error; - } - - BT_COMP_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p", - in_stream, out_stream); - - goto end; -error: - out_stream = NULL; -end: - return out_stream; -} - -bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps, - const bt_stream *in_stream) -{ - struct trace_ir_data_maps *d_maps; - - BT_ASSERT_DBG(ir_maps); - BT_ASSERT_DBG(in_stream); - - d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream); - /* Return the mapped stream. */ - return borrow_mapped_stream(d_maps, in_stream); -} - -static inline -bt_event_class *borrow_mapped_event_class(struct trace_ir_metadata_maps *md_maps, - const bt_event_class *in_event_class) -{ - return g_hash_table_lookup(md_maps->event_class_map, - (gpointer) in_event_class); -} - -bt_event_class *trace_ir_mapping_create_new_mapped_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *md_maps; - const bt_stream_class *in_stream_class; - bt_stream_class *out_stream_class; - bt_event_class *out_event_class; - - BT_COMP_LOGD("Creating new mapped event class: in-ec-addr=%p", - in_event_class); - - BT_ASSERT(ir_maps); - BT_ASSERT(in_event_class); - - in_stream_class = bt_event_class_borrow_stream_class_const(in_event_class); - - BT_ASSERT(in_stream_class); - - md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, - in_stream_class); - - BT_ASSERT(md_maps); - BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class)); - - /* Get the right output stream class to add the new event class to it. */ - out_stream_class = trace_ir_mapping_borrow_mapped_stream_class( - ir_maps, in_stream_class); - BT_ASSERT(out_stream_class); - - /* Create an output event class. */ - out_event_class = bt_event_class_create_with_id(out_stream_class, - bt_event_class_get_id(in_event_class)); - if (!out_event_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output event class"); - goto end; - } - - /* Add it to the mapping. The mapping now owns out_event_class. */ - g_hash_table_insert(md_maps->event_class_map, (gpointer) in_event_class, - out_event_class); - - /* Copy the content over to the output event class. */ - status = copy_event_class_content(ir_maps, in_event_class, - out_event_class); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output event class: " - "in-ec-addr=%p, out-ec-addr=%p", in_event_class, - out_event_class); - goto error; - } - - BT_COMP_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p", - in_event_class, out_event_class); - - goto end; -error: - out_event_class = NULL; -end: - return out_event_class; -} - -bt_event_class *trace_ir_mapping_borrow_mapped_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class) -{ - struct trace_ir_metadata_maps *md_maps; - - BT_ASSERT_DBG(ir_maps); - BT_ASSERT_DBG(in_event_class); - - md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, - in_event_class); - - /* Return the mapped event_class. */ - return borrow_mapped_event_class(md_maps, in_event_class); -} - -static inline -bt_packet *borrow_mapped_packet(struct trace_ir_data_maps *d_maps, - const bt_packet *in_packet) -{ - BT_ASSERT_DBG(d_maps); - BT_ASSERT_DBG(in_packet); - - return g_hash_table_lookup(d_maps->packet_map, (gpointer) in_packet); -} - -bt_packet *trace_ir_mapping_create_new_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet) -{ - bt_self_component *self_comp = ir_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_data_maps *d_maps; - const bt_stream *in_stream; - const bt_trace *in_trace; - bt_packet *out_packet; - bt_stream *out_stream; - - BT_COMP_LOGD("Creating new mapped packet: in-p-addr=%p", in_packet); - - in_stream = bt_packet_borrow_stream_const(in_packet); - in_trace = bt_stream_borrow_trace_const(in_stream); - d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace); - - /* There should never be a mapped packet already. */ - BT_ASSERT(!borrow_mapped_packet(d_maps, in_packet)); - BT_ASSERT(in_stream); - - /* Get output stream corresponding to this input stream. */ - out_stream = borrow_mapped_stream(d_maps, in_stream); - BT_ASSERT(out_stream); - - /* Create the output packet. */ - out_packet = bt_packet_create(out_stream); - if (!out_packet) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error create output packet"); - goto error; - } - - /* Add it to the mapping. The mapping now owns out_packet. */ - g_hash_table_insert(d_maps->packet_map, (gpointer) in_packet, - out_packet); - - /* Copy the content over to the output packet. */ - status = copy_packet_content(in_packet, out_packet, ir_maps->log_level, - ir_maps->self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copy content to output packet: " - "in-p-addr=%p, out-p-addr=%p", in_packet, out_packet); - goto error; - } - - BT_COMP_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p", - in_packet, out_packet); - - goto end; -error: - out_packet = NULL; -end: - return out_packet; -} - -bt_packet *trace_ir_mapping_borrow_mapped_packet(struct trace_ir_maps *ir_maps, - const bt_packet *in_packet) -{ - struct trace_ir_data_maps *d_maps; - BT_ASSERT_DBG(ir_maps); - BT_ASSERT_DBG(in_packet); - - d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); - - return borrow_mapped_packet(d_maps, in_packet); -} - -void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps, - const bt_packet *in_packet) -{ - struct trace_ir_data_maps *d_maps; - gboolean ret; - - BT_ASSERT(ir_maps); - BT_ASSERT(in_packet); - - d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); - - ret = g_hash_table_remove(d_maps->packet_map, in_packet); - - BT_ASSERT(ret); -} - -void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps, - const bt_stream *in_stream) -{ - struct trace_ir_data_maps *d_maps; - gboolean ret; - - BT_ASSERT(ir_maps); - BT_ASSERT(in_stream); - - d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream); - - ret = g_hash_table_remove(d_maps->stream_map, in_stream); - - BT_ASSERT(ret); -} - -static -void trace_ir_metadata_maps_remove_func(const bt_trace_class *in_trace_class, - void *data) -{ - struct trace_ir_maps *maps = (struct trace_ir_maps *) data; - if (maps->metadata_maps) { - gboolean ret; - ret = g_hash_table_remove(maps->metadata_maps, - (gpointer) in_trace_class); - BT_ASSERT(ret); - } -} - -static -void trace_ir_data_maps_remove_func(const bt_trace *in_trace, void *data) -{ - struct trace_ir_maps *maps = (struct trace_ir_maps *) data; - if (maps->data_maps) { - gboolean ret; - ret = g_hash_table_remove(maps->data_maps, (gpointer) in_trace); - BT_ASSERT(ret); - } -} - -struct trace_ir_data_maps *trace_ir_data_maps_create(struct trace_ir_maps *ir_maps, - const bt_trace *in_trace) -{ - bt_self_component *self_comp = ir_maps->self_comp; - bt_trace_add_listener_status add_listener_status; - struct trace_ir_data_maps *d_maps = g_new0(struct trace_ir_data_maps, 1); - - if (!d_maps) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error allocating trace_ir_maps"); - goto error; - } - - d_maps->log_level = ir_maps->log_level; - d_maps->self_comp = ir_maps->self_comp; - d_maps->input_trace = in_trace; - - /* Create the hashtables used to map data objects. */ - d_maps->stream_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL,(GDestroyNotify) bt_stream_put_ref); - d_maps->packet_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL,(GDestroyNotify) bt_packet_put_ref); - - add_listener_status = bt_trace_add_destruction_listener( - in_trace, trace_ir_data_maps_remove_func, - ir_maps, &d_maps->destruction_listener_id); - BT_ASSERT(add_listener_status == BT_TRACE_ADD_LISTENER_STATUS_OK); - -error: - return d_maps; -} - -struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( - struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class) -{ - bt_self_component *self_comp = ir_maps->self_comp; - bt_trace_class_add_listener_status add_listener_status; - struct trace_ir_metadata_maps *md_maps = - g_new0(struct trace_ir_metadata_maps, 1); - - if (!md_maps) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error allocating trace_ir_maps"); - goto error; - } - - md_maps->log_level = ir_maps->log_level; - md_maps->self_comp = ir_maps->self_comp; - md_maps->input_trace_class = in_trace_class; - /* - * Create the field class resolving context. This is needed to keep - * track of the field class already copied in order to do the field - * path resolution correctly. - */ - md_maps->fc_resolving_ctx = - g_new0(struct field_class_resolving_context, 1); - if (!md_maps->fc_resolving_ctx) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error allocating field_class_resolving_context"); - goto error; - } - - /* Create the hashtables used to map metadata objects. */ - md_maps->stream_class_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) bt_stream_class_put_ref); - md_maps->event_class_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) bt_event_class_put_ref); - md_maps->field_class_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) bt_field_class_put_ref); - md_maps->clock_class_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) bt_clock_class_put_ref); - - add_listener_status = bt_trace_class_add_destruction_listener( - in_trace_class, trace_ir_metadata_maps_remove_func, - ir_maps, &md_maps->destruction_listener_id); - BT_ASSERT(add_listener_status == BT_TRACE_CLASS_ADD_LISTENER_STATUS_OK); - -error: - return md_maps; -} - -void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps) -{ - bt_trace_remove_listener_status status; - - if (!maps) { - return; - } - - if (maps->packet_map) { - g_hash_table_destroy(maps->packet_map); - } - - if (maps->stream_map) { - g_hash_table_destroy(maps->stream_map); - } - - if (maps->output_trace) { - bt_trace_put_ref(maps->output_trace); - } - - status = bt_trace_remove_destruction_listener(maps->input_trace, - maps->destruction_listener_id); - if (status != BT_TRACE_REMOVE_LISTENER_STATUS_OK) { - BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, maps->log_level, - maps->self_comp, - "Trace destruction listener removal failed."); - bt_current_thread_clear_error(); - } - - g_free(maps); -} - -void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps) -{ - bt_trace_class_remove_listener_status status; - - if (!maps) { - return; - } - - if (maps->stream_class_map) { - g_hash_table_destroy(maps->stream_class_map); - } - - if (maps->event_class_map) { - g_hash_table_destroy(maps->event_class_map); - } - - if (maps->field_class_map) { - g_hash_table_destroy(maps->field_class_map); - } - - if (maps->clock_class_map) { - g_hash_table_destroy(maps->clock_class_map); - } - - g_free(maps->fc_resolving_ctx); - - if (maps->output_trace_class) { - bt_trace_class_put_ref(maps->output_trace_class); - } - - status = bt_trace_class_remove_destruction_listener( - maps->input_trace_class, maps->destruction_listener_id); - if (status != BT_TRACE_CLASS_REMOVE_LISTENER_STATUS_OK) { - BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, maps->log_level, - maps->self_comp, - "Trace destruction listener removal failed."); - bt_current_thread_clear_error(); - } - - g_free(maps); -} - -void trace_ir_maps_clear(struct trace_ir_maps *maps) -{ - if (maps->data_maps) { - g_hash_table_remove_all(maps->data_maps); - } - - if (maps->metadata_maps) { - g_hash_table_remove_all(maps->metadata_maps); - } -} - -void trace_ir_maps_destroy(struct trace_ir_maps *maps) -{ - if (!maps) { - return; - } - - g_free(maps->debug_info_field_class_name); - - if (maps->data_maps) { - g_hash_table_destroy(maps->data_maps); - maps->data_maps = NULL; - } - - if (maps->metadata_maps) { - g_hash_table_destroy(maps->metadata_maps); - maps->metadata_maps = NULL; - } - - g_free(maps); -} - -struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, - const char *debug_info_field_name, bt_logging_level log_level) -{ - struct trace_ir_maps *ir_maps = g_new0(struct trace_ir_maps, 1); - if (!ir_maps) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, - "Error allocating trace_ir_maps"); - goto error; - } - - ir_maps->log_level = log_level; - ir_maps->self_comp = self_comp; - - /* Copy debug info field name received from the user. */ - ir_maps->debug_info_field_class_name = g_strdup(debug_info_field_name); - if (!ir_maps->debug_info_field_class_name) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy debug info field name"); - goto error; - } - - ir_maps->self_comp = self_comp; - - ir_maps->data_maps = g_hash_table_new_full(g_direct_hash, - g_direct_equal, (GDestroyNotify) NULL, - (GDestroyNotify) trace_ir_data_maps_destroy); - - ir_maps->metadata_maps = g_hash_table_new_full(g_direct_hash, - g_direct_equal, (GDestroyNotify) NULL, - (GDestroyNotify) trace_ir_metadata_maps_destroy); - - goto end; -error: - trace_ir_maps_destroy(ir_maps); - ir_maps = NULL; -end: - return ir_maps; -} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.cpp b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.cpp new file mode 100644 index 00000000..815bb82f --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.cpp @@ -0,0 +1,764 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Mapping of IR metadata and data object between input and output + * trace + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP (ir_maps->self_comp) +#define BT_LOG_OUTPUT_LEVEL (ir_maps->log_level) +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-MAPPING" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include + +#include "debug-info.hpp" +#include "trace-ir-data-copy.hpp" +#include "trace-ir-mapping.hpp" +#include "trace-ir-metadata-copy.hpp" + +static +bt_trace_class *create_new_mapped_trace_class(struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *metadata_maps; + + BT_COMP_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class); + + BT_ASSERT(ir_maps); + BT_ASSERT(in_trace_class); + + metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, + in_trace_class); + + BT_ASSERT(!metadata_maps->output_trace_class); + + /* Create the output trace class. */ + metadata_maps->output_trace_class = + bt_trace_class_create(ir_maps->self_comp); + if (!metadata_maps->output_trace_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error create output trace class"); + goto error; + } + + /* Copy the content over and add to the mapping. */ + status = copy_trace_class_content(ir_maps, in_trace_class, + metadata_maps->output_trace_class, ir_maps->log_level, + ir_maps->self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output trace class" + "in-tc-addr=%p, out-tc-addr=%p", in_trace_class, + metadata_maps->output_trace_class); + goto error; + } + + BT_COMP_LOGD("Created new mapped trace class: " + "in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, metadata_maps->output_trace_class); + + goto end; +error: + BT_TRACE_CLASS_PUT_REF_AND_RESET(metadata_maps->output_trace_class); +end: + return metadata_maps->output_trace_class; +} + +static +bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps, + const bt_trace *in_trace) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *metadata_maps; + const bt_trace_class *in_trace_class; + bt_trace *out_trace; + + BT_COMP_LOGD("Creating new mapped trace: in-t-addr=%p", in_trace); + BT_ASSERT(ir_maps); + BT_ASSERT(in_trace); + + in_trace_class = bt_trace_borrow_class_const(in_trace); + metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, + in_trace_class); + + if (!metadata_maps->output_trace_class) { + /* + * If there is no output trace class yet, create a one and add + * it to the mapping. + */ + metadata_maps->output_trace_class = + create_new_mapped_trace_class(ir_maps, in_trace_class); + if (!metadata_maps->output_trace_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error create output trace class"); + out_trace = NULL; + goto end; + } + } + + /* Create the output trace from the output trace class. */ + out_trace = bt_trace_create(metadata_maps->output_trace_class); + if (!out_trace) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error create output trace"); + goto end; + } + + /* Copy the content over to the output trace. */ + status = copy_trace_content(in_trace, out_trace, ir_maps->log_level, + ir_maps->self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output trace" + "in-t-addr=%p, out-t-addr=%p", in_trace, out_trace); + goto error; + } + + BT_COMP_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p", + in_trace, out_trace); + goto end; + +error: + BT_TRACE_PUT_REF_AND_RESET(out_trace); +end: + return out_trace; +} + +bt_stream_class *trace_ir_mapping_borrow_mapped_stream_class( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class) +{ + BT_ASSERT_DBG(ir_maps); + BT_ASSERT_DBG(in_stream_class); + + struct trace_ir_metadata_maps *md_maps = + borrow_metadata_maps_from_input_stream_class(ir_maps, + in_stream_class); + return static_cast(g_hash_table_lookup(md_maps->stream_class_map, + (gpointer) in_stream_class)); +} + +bt_stream_class *trace_ir_mapping_create_new_mapped_stream_class( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *md_maps; + bt_stream_class *out_stream_class; + + BT_COMP_LOGD("Creating new mapped stream class: in-sc-addr=%p", + in_stream_class); + + BT_ASSERT(ir_maps); + BT_ASSERT(in_stream_class); + BT_ASSERT(!trace_ir_mapping_borrow_mapped_stream_class(ir_maps, + in_stream_class)); + + md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, + in_stream_class); + + BT_ASSERT(md_maps); + + /* Create the output stream class. */ + out_stream_class = bt_stream_class_create_with_id( + md_maps->output_trace_class, + bt_stream_class_get_id(in_stream_class)); + if (!out_stream_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error create output stream class"); + goto end; + } + + /* Add it to the mapping. The mapping now owns out_stream_class. */ + g_hash_table_insert(md_maps->stream_class_map, + (gpointer) in_stream_class, out_stream_class); + + /* Copy the content over to the output stream class. */ + status = copy_stream_class_content(ir_maps, in_stream_class, + out_stream_class); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output stream class: " + "in-sc-addr=%p, out-sc-addr=%p", in_stream_class, + out_stream_class); + goto error; + } + + BT_COMP_LOGD("Created new mapped stream class: " + "in-sc-addr=%p, out-sc-addr=%p", + in_stream_class, out_stream_class); + + goto end; +error: + out_stream_class = NULL; +end: + return out_stream_class; +} + +static +bt_stream *borrow_mapped_stream(struct trace_ir_data_maps *d_maps, + const bt_stream *in_stream) +{ + BT_ASSERT_DBG(d_maps); + BT_ASSERT_DBG(in_stream); + + return static_cast(g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream)); +} + +bt_stream *trace_ir_mapping_create_new_mapped_stream( + struct trace_ir_maps *ir_maps, const bt_stream *in_stream) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_data_maps *d_maps; + const bt_stream_class *in_stream_class; + const bt_trace *in_trace; + bt_stream_class *out_stream_class; + bt_stream *out_stream = NULL; + + BT_ASSERT(ir_maps); + BT_ASSERT(in_stream); + BT_COMP_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream); + + in_trace = bt_stream_borrow_trace_const(in_stream); + + d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace); + if (!d_maps->output_trace) { + /* Create the output trace for this input trace. */ + d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace); + if (!d_maps->output_trace) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating mapped trace"); + goto error; + } + } + + BT_ASSERT(d_maps->output_trace); + BT_ASSERT(!borrow_mapped_stream(d_maps, in_stream)); + + in_stream_class = bt_stream_borrow_class_const(in_stream); + out_stream_class = trace_ir_mapping_borrow_mapped_stream_class(ir_maps, + in_stream_class); + + if (!out_stream_class) { + /* Create the output stream class for this input stream class. */ + out_stream_class = trace_ir_mapping_create_new_mapped_stream_class( + ir_maps, in_stream_class); + if (!out_stream_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating mapped stream class"); + goto error; + } + } + BT_ASSERT(out_stream_class); + + /* Create the output stream for this input stream. */ + out_stream = bt_stream_create_with_id(out_stream_class, + d_maps->output_trace, bt_stream_get_id(in_stream)); + if (!out_stream) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output stream"); + goto error; + } + + /* Add it to the mapping. The mapping now owns out_stream.*/ + g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream, + out_stream); + + /* Copy the content over to the output stream. */ + status = copy_stream_content(in_stream, out_stream, ir_maps->log_level, + ir_maps->self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output stream: " + "in-s-addr=%p, out-s-addr=%p", in_stream, out_stream); + goto error; + } + + BT_COMP_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p", + in_stream, out_stream); + + goto end; +error: + out_stream = NULL; +end: + return out_stream; +} + +bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps, + const bt_stream *in_stream) +{ + struct trace_ir_data_maps *d_maps; + + BT_ASSERT_DBG(ir_maps); + BT_ASSERT_DBG(in_stream); + + d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream); + /* Return the mapped stream. */ + return borrow_mapped_stream(d_maps, in_stream); +} + +static inline +bt_event_class *borrow_mapped_event_class(struct trace_ir_metadata_maps *md_maps, + const bt_event_class *in_event_class) +{ + return static_cast(g_hash_table_lookup(md_maps->event_class_map, + (gpointer) in_event_class)); +} + +bt_event_class *trace_ir_mapping_create_new_mapped_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *md_maps; + const bt_stream_class *in_stream_class; + bt_stream_class *out_stream_class; + bt_event_class *out_event_class; + + BT_COMP_LOGD("Creating new mapped event class: in-ec-addr=%p", + in_event_class); + + BT_ASSERT(ir_maps); + BT_ASSERT(in_event_class); + + in_stream_class = bt_event_class_borrow_stream_class_const(in_event_class); + + BT_ASSERT(in_stream_class); + + md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, + in_stream_class); + + BT_ASSERT(md_maps); + BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class)); + + /* Get the right output stream class to add the new event class to it. */ + out_stream_class = trace_ir_mapping_borrow_mapped_stream_class( + ir_maps, in_stream_class); + BT_ASSERT(out_stream_class); + + /* Create an output event class. */ + out_event_class = bt_event_class_create_with_id(out_stream_class, + bt_event_class_get_id(in_event_class)); + if (!out_event_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output event class"); + goto end; + } + + /* Add it to the mapping. The mapping now owns out_event_class. */ + g_hash_table_insert(md_maps->event_class_map, (gpointer) in_event_class, + out_event_class); + + /* Copy the content over to the output event class. */ + status = copy_event_class_content(ir_maps, in_event_class, + out_event_class); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output event class: " + "in-ec-addr=%p, out-ec-addr=%p", in_event_class, + out_event_class); + goto error; + } + + BT_COMP_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p", + in_event_class, out_event_class); + + goto end; +error: + out_event_class = NULL; +end: + return out_event_class; +} + +bt_event_class *trace_ir_mapping_borrow_mapped_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class) +{ + struct trace_ir_metadata_maps *md_maps; + + BT_ASSERT_DBG(ir_maps); + BT_ASSERT_DBG(in_event_class); + + md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, + in_event_class); + + /* Return the mapped event_class. */ + return borrow_mapped_event_class(md_maps, in_event_class); +} + +static inline +bt_packet *borrow_mapped_packet(struct trace_ir_data_maps *d_maps, + const bt_packet *in_packet) +{ + BT_ASSERT_DBG(d_maps); + BT_ASSERT_DBG(in_packet); + + return static_cast(g_hash_table_lookup(d_maps->packet_map, (gpointer) in_packet)); +} + +bt_packet *trace_ir_mapping_create_new_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet) +{ + bt_self_component *self_comp = ir_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_data_maps *d_maps; + const bt_stream *in_stream; + const bt_trace *in_trace; + bt_packet *out_packet; + bt_stream *out_stream; + + BT_COMP_LOGD("Creating new mapped packet: in-p-addr=%p", in_packet); + + in_stream = bt_packet_borrow_stream_const(in_packet); + in_trace = bt_stream_borrow_trace_const(in_stream); + d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace); + + /* There should never be a mapped packet already. */ + BT_ASSERT(!borrow_mapped_packet(d_maps, in_packet)); + BT_ASSERT(in_stream); + + /* Get output stream corresponding to this input stream. */ + out_stream = borrow_mapped_stream(d_maps, in_stream); + BT_ASSERT(out_stream); + + /* Create the output packet. */ + out_packet = bt_packet_create(out_stream); + if (!out_packet) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error create output packet"); + goto error; + } + + /* Add it to the mapping. The mapping now owns out_packet. */ + g_hash_table_insert(d_maps->packet_map, (gpointer) in_packet, + out_packet); + + /* Copy the content over to the output packet. */ + status = copy_packet_content(in_packet, out_packet, ir_maps->log_level, + ir_maps->self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copy content to output packet: " + "in-p-addr=%p, out-p-addr=%p", in_packet, out_packet); + goto error; + } + + BT_COMP_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p", + in_packet, out_packet); + + goto end; +error: + out_packet = NULL; +end: + return out_packet; +} + +bt_packet *trace_ir_mapping_borrow_mapped_packet(struct trace_ir_maps *ir_maps, + const bt_packet *in_packet) +{ + struct trace_ir_data_maps *d_maps; + BT_ASSERT_DBG(ir_maps); + BT_ASSERT_DBG(in_packet); + + d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); + + return borrow_mapped_packet(d_maps, in_packet); +} + +void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps, + const bt_packet *in_packet) +{ + struct trace_ir_data_maps *d_maps; + gboolean ret; + + BT_ASSERT(ir_maps); + BT_ASSERT(in_packet); + + d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); + + ret = g_hash_table_remove(d_maps->packet_map, in_packet); + + BT_ASSERT(ret); +} + +void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps, + const bt_stream *in_stream) +{ + struct trace_ir_data_maps *d_maps; + gboolean ret; + + BT_ASSERT(ir_maps); + BT_ASSERT(in_stream); + + d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream); + + ret = g_hash_table_remove(d_maps->stream_map, in_stream); + + BT_ASSERT(ret); +} + +static +void trace_ir_metadata_maps_remove_func(const bt_trace_class *in_trace_class, + void *data) +{ + struct trace_ir_maps *maps = (struct trace_ir_maps *) data; + if (maps->metadata_maps) { + gboolean ret; + ret = g_hash_table_remove(maps->metadata_maps, + (gpointer) in_trace_class); + BT_ASSERT(ret); + } +} + +static +void trace_ir_data_maps_remove_func(const bt_trace *in_trace, void *data) +{ + struct trace_ir_maps *maps = (struct trace_ir_maps *) data; + if (maps->data_maps) { + gboolean ret; + ret = g_hash_table_remove(maps->data_maps, (gpointer) in_trace); + BT_ASSERT(ret); + } +} + +struct trace_ir_data_maps *trace_ir_data_maps_create(struct trace_ir_maps *ir_maps, + const bt_trace *in_trace) +{ + bt_self_component *self_comp = ir_maps->self_comp; + bt_trace_add_listener_status add_listener_status; + struct trace_ir_data_maps *d_maps = g_new0(struct trace_ir_data_maps, 1); + + if (!d_maps) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error allocating trace_ir_maps"); + goto error; + } + + d_maps->log_level = ir_maps->log_level; + d_maps->self_comp = ir_maps->self_comp; + d_maps->input_trace = in_trace; + + /* Create the hashtables used to map data objects. */ + d_maps->stream_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL,(GDestroyNotify) bt_stream_put_ref); + d_maps->packet_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL,(GDestroyNotify) bt_packet_put_ref); + + add_listener_status = bt_trace_add_destruction_listener( + in_trace, trace_ir_data_maps_remove_func, + ir_maps, &d_maps->destruction_listener_id); + BT_ASSERT(add_listener_status == BT_TRACE_ADD_LISTENER_STATUS_OK); + +error: + return d_maps; +} + +struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( + struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class) +{ + bt_self_component *self_comp = ir_maps->self_comp; + bt_trace_class_add_listener_status add_listener_status; + struct trace_ir_metadata_maps *md_maps = + g_new0(struct trace_ir_metadata_maps, 1); + + if (!md_maps) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error allocating trace_ir_maps"); + goto error; + } + + md_maps->log_level = ir_maps->log_level; + md_maps->self_comp = ir_maps->self_comp; + md_maps->input_trace_class = in_trace_class; + /* + * Create the field class resolving context. This is needed to keep + * track of the field class already copied in order to do the field + * path resolution correctly. + */ + md_maps->fc_resolving_ctx = + g_new0(struct field_class_resolving_context, 1); + if (!md_maps->fc_resolving_ctx) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error allocating field_class_resolving_context"); + goto error; + } + + /* Create the hashtables used to map metadata objects. */ + md_maps->stream_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) bt_stream_class_put_ref); + md_maps->event_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) bt_event_class_put_ref); + md_maps->field_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) bt_field_class_put_ref); + md_maps->clock_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) bt_clock_class_put_ref); + + add_listener_status = bt_trace_class_add_destruction_listener( + in_trace_class, trace_ir_metadata_maps_remove_func, + ir_maps, &md_maps->destruction_listener_id); + BT_ASSERT(add_listener_status == BT_TRACE_CLASS_ADD_LISTENER_STATUS_OK); + +error: + return md_maps; +} + +void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps) +{ + bt_trace_remove_listener_status status; + + if (!maps) { + return; + } + + if (maps->packet_map) { + g_hash_table_destroy(maps->packet_map); + } + + if (maps->stream_map) { + g_hash_table_destroy(maps->stream_map); + } + + if (maps->output_trace) { + bt_trace_put_ref(maps->output_trace); + } + + status = bt_trace_remove_destruction_listener(maps->input_trace, + maps->destruction_listener_id); + if (status != BT_TRACE_REMOVE_LISTENER_STATUS_OK) { + BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, maps->log_level, + maps->self_comp, + "Trace destruction listener removal failed."); + bt_current_thread_clear_error(); + } + + g_free(maps); +} + +void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps) +{ + bt_trace_class_remove_listener_status status; + + if (!maps) { + return; + } + + if (maps->stream_class_map) { + g_hash_table_destroy(maps->stream_class_map); + } + + if (maps->event_class_map) { + g_hash_table_destroy(maps->event_class_map); + } + + if (maps->field_class_map) { + g_hash_table_destroy(maps->field_class_map); + } + + if (maps->clock_class_map) { + g_hash_table_destroy(maps->clock_class_map); + } + + g_free(maps->fc_resolving_ctx); + + if (maps->output_trace_class) { + bt_trace_class_put_ref(maps->output_trace_class); + } + + status = bt_trace_class_remove_destruction_listener( + maps->input_trace_class, maps->destruction_listener_id); + if (status != BT_TRACE_CLASS_REMOVE_LISTENER_STATUS_OK) { + BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, maps->log_level, + maps->self_comp, + "Trace destruction listener removal failed."); + bt_current_thread_clear_error(); + } + + g_free(maps); +} + +void trace_ir_maps_clear(struct trace_ir_maps *maps) +{ + if (maps->data_maps) { + g_hash_table_remove_all(maps->data_maps); + } + + if (maps->metadata_maps) { + g_hash_table_remove_all(maps->metadata_maps); + } +} + +void trace_ir_maps_destroy(struct trace_ir_maps *maps) +{ + if (!maps) { + return; + } + + g_free(maps->debug_info_field_class_name); + + if (maps->data_maps) { + g_hash_table_destroy(maps->data_maps); + maps->data_maps = NULL; + } + + if (maps->metadata_maps) { + g_hash_table_destroy(maps->metadata_maps); + maps->metadata_maps = NULL; + } + + g_free(maps); +} + +struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, + const char *debug_info_field_name, bt_logging_level log_level) +{ + struct trace_ir_maps *ir_maps = g_new0(struct trace_ir_maps, 1); + if (!ir_maps) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, + "Error allocating trace_ir_maps"); + goto error; + } + + ir_maps->log_level = log_level; + ir_maps->self_comp = self_comp; + + /* Copy debug info field name received from the user. */ + ir_maps->debug_info_field_class_name = g_strdup(debug_info_field_name); + if (!ir_maps->debug_info_field_class_name) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy debug info field name"); + goto error; + } + + ir_maps->self_comp = self_comp; + + ir_maps->data_maps = g_hash_table_new_full(g_direct_hash, + g_direct_equal, (GDestroyNotify) NULL, + (GDestroyNotify) trace_ir_data_maps_destroy); + + ir_maps->metadata_maps = g_hash_table_new_full(g_direct_hash, + g_direct_equal, (GDestroyNotify) NULL, + (GDestroyNotify) trace_ir_metadata_maps_destroy); + + goto end; +error: + trace_ir_maps_destroy(ir_maps); + ir_maps = NULL; +end: + return ir_maps; +} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.h b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.h deleted file mode 100644 index b4d7445b..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com> - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_H - -#include - -#include "common/assert.h" -#include "common/macros.h" -#include - -#include "debug-info.h" - -enum debug_info_trace_ir_mapping_status { - DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK = 0, - DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR = -12, -}; - -/* Used to resolve field paths for dynamic arrays and variant field classes. */ -struct field_class_resolving_context { - /* Weak reference. Owned by input stream class. */ - const bt_field_class *packet_context; - /* Weak reference. Owned by input stream class. */ - const bt_field_class *event_common_context; - /* Weak reference. Owned by input event class. */ - const bt_field_class *event_specific_context; - /* Weak reference. Owned by input event class. */ - const bt_field_class *event_payload; -}; - -struct trace_ir_metadata_maps { - bt_logging_level log_level; - bt_self_component *self_comp; - const bt_trace_class *input_trace_class; - bt_trace_class *output_trace_class; - - /* - * Map between input stream class and its corresponding output stream - * class. - * input stream class: weak reference. Owned by an upstream - * component. - * output stream class: owned by this structure. - */ - GHashTable *stream_class_map; - - /* - * Map between input event class and its corresponding output event - * class. - * input event class: weak reference. Owned by an upstream component. - * output event class: owned by this structure. - */ - GHashTable *event_class_map; - - /* - * Map between input field class and its corresponding output field - * class. - * input field class: weak reference. Owned by an upstream component. - * output field class: owned by this structure. - */ - GHashTable *field_class_map; - - /* - * Map between input clock class and its corresponding output clock - * class. - * input clock class: weak reference. Owned by an upstream component. - * output clock class: owned by this structure. - */ - GHashTable *clock_class_map; - - struct field_class_resolving_context *fc_resolving_ctx; - - bt_listener_id destruction_listener_id; -}; - -struct trace_ir_data_maps { - bt_logging_level log_level; - bt_self_component *self_comp; - const bt_trace *input_trace; - bt_trace *output_trace; - - /* - * Map between input stream its corresponding output stream. - * input stream: weak reference. Owned by an upstream component. - * output stream: owned by this structure. - */ - GHashTable *stream_map; - - /* - * Map between input packet its corresponding output packet. - * input packet: weak reference. Owned by an upstream packet component. - * output packet: owned by this structure. - */ - GHashTable *packet_map; - - bt_listener_id destruction_listener_id; -}; - -struct trace_ir_maps { - bt_logging_level log_level; - - /* - * input trace -> trace_ir_data_maps. - * input trace: weak reference. Owned by an upstream component. - * trace_ir_data_maps: Owned by this structure. - */ - GHashTable *data_maps; - - /* - * input trace class -> trace_ir_metadata_maps. - * input trace class: weak reference. Owned by an upstream component. - * trace_ir_metadata_maps: Owned by this structure. - */ - GHashTable *metadata_maps; - - char *debug_info_field_class_name; - - bt_self_component *self_comp; -}; - -struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, - const char *debug_info_field_name, bt_logging_level log_level); - -void trace_ir_maps_clear(struct trace_ir_maps *maps); - -void trace_ir_maps_destroy(struct trace_ir_maps *maps); - -struct trace_ir_data_maps *trace_ir_data_maps_create( - struct trace_ir_maps *ir_maps, - const bt_trace *in_trace); - -void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps); - -struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( - struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class); - -void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps); - -bt_stream_class *trace_ir_mapping_create_new_mapped_stream_class( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class); - -bt_stream_class *trace_ir_mapping_borrow_mapped_stream_class( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class); - -bt_stream *trace_ir_mapping_create_new_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -bt_stream *trace_ir_mapping_borrow_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -void trace_ir_mapping_remove_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -bt_event_class *trace_ir_mapping_create_new_mapped_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class); - -bt_event_class *trace_ir_mapping_borrow_mapped_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class); - -bt_packet *trace_ir_mapping_create_new_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet); - -bt_packet *trace_ir_mapping_borrow_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet); - -void trace_ir_mapping_remove_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet); - -static inline -struct trace_ir_data_maps *borrow_data_maps_from_input_trace( - struct trace_ir_maps *ir_maps, const bt_trace *in_trace) -{ - BT_ASSERT(ir_maps); - BT_ASSERT(in_trace); - - struct trace_ir_data_maps *d_maps = - g_hash_table_lookup(ir_maps->data_maps, (gpointer) in_trace); - if (!d_maps) { - d_maps = trace_ir_data_maps_create(ir_maps, in_trace); - g_hash_table_insert(ir_maps->data_maps, (gpointer) in_trace, d_maps); - } - - return d_maps; -} - -static inline -struct trace_ir_data_maps *borrow_data_maps_from_input_stream( - struct trace_ir_maps *ir_maps, const bt_stream *in_stream) -{ - BT_ASSERT(ir_maps); - BT_ASSERT(in_stream); - - return borrow_data_maps_from_input_trace(ir_maps, - bt_stream_borrow_trace_const(in_stream)); -} - -static inline -struct trace_ir_data_maps *borrow_data_maps_from_input_packet( - struct trace_ir_maps *ir_maps, const bt_packet *in_packet) -{ - BT_ASSERT(ir_maps); - BT_ASSERT(in_packet); - - return borrow_data_maps_from_input_stream(ir_maps, - bt_packet_borrow_stream_const(in_packet)); -} - -static inline -struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_trace_class( - struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class) -{ - BT_ASSERT(ir_maps); - BT_ASSERT(in_trace_class); - - struct trace_ir_metadata_maps *md_maps = - g_hash_table_lookup(ir_maps->metadata_maps, - (gpointer) in_trace_class); - if (!md_maps) { - md_maps = trace_ir_metadata_maps_create(ir_maps, in_trace_class); - g_hash_table_insert(ir_maps->metadata_maps, - (gpointer) in_trace_class, md_maps); - } - - return md_maps; -} - -static inline -struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_stream_class( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class) { - - BT_ASSERT(in_stream_class); - - return borrow_metadata_maps_from_input_trace_class(ir_maps, - bt_stream_class_borrow_trace_class_const(in_stream_class)); -} - -static inline -struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class) { - - BT_ASSERT(in_event_class); - - return borrow_metadata_maps_from_input_stream_class(ir_maps, - bt_event_class_borrow_stream_class_const(in_event_class)); -} - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_H */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.hpp b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.hpp new file mode 100644 index 00000000..c728543e --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.hpp @@ -0,0 +1,266 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com> + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_HPP + +#include + +#include "common/assert.h" +#include "common/macros.h" +#include + +#include "debug-info.hpp" + +enum debug_info_trace_ir_mapping_status { + DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK = 0, + DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR = -12, +}; + +/* Used to resolve field paths for dynamic arrays and variant field classes. */ +struct field_class_resolving_context { + /* Weak reference. Owned by input stream class. */ + const bt_field_class *packet_context; + /* Weak reference. Owned by input stream class. */ + const bt_field_class *event_common_context; + /* Weak reference. Owned by input event class. */ + const bt_field_class *event_specific_context; + /* Weak reference. Owned by input event class. */ + const bt_field_class *event_payload; +}; + +struct trace_ir_metadata_maps { + bt_logging_level log_level; + bt_self_component *self_comp; + const bt_trace_class *input_trace_class; + bt_trace_class *output_trace_class; + + /* + * Map between input stream class and its corresponding output stream + * class. + * input stream class: weak reference. Owned by an upstream + * component. + * output stream class: owned by this structure. + */ + GHashTable *stream_class_map; + + /* + * Map between input event class and its corresponding output event + * class. + * input event class: weak reference. Owned by an upstream component. + * output event class: owned by this structure. + */ + GHashTable *event_class_map; + + /* + * Map between input field class and its corresponding output field + * class. + * input field class: weak reference. Owned by an upstream component. + * output field class: owned by this structure. + */ + GHashTable *field_class_map; + + /* + * Map between input clock class and its corresponding output clock + * class. + * input clock class: weak reference. Owned by an upstream component. + * output clock class: owned by this structure. + */ + GHashTable *clock_class_map; + + struct field_class_resolving_context *fc_resolving_ctx; + + bt_listener_id destruction_listener_id; +}; + +struct trace_ir_data_maps { + bt_logging_level log_level; + bt_self_component *self_comp; + const bt_trace *input_trace; + bt_trace *output_trace; + + /* + * Map between input stream its corresponding output stream. + * input stream: weak reference. Owned by an upstream component. + * output stream: owned by this structure. + */ + GHashTable *stream_map; + + /* + * Map between input packet its corresponding output packet. + * input packet: weak reference. Owned by an upstream packet component. + * output packet: owned by this structure. + */ + GHashTable *packet_map; + + bt_listener_id destruction_listener_id; +}; + +struct trace_ir_maps { + bt_logging_level log_level; + + /* + * input trace -> trace_ir_data_maps. + * input trace: weak reference. Owned by an upstream component. + * trace_ir_data_maps: Owned by this structure. + */ + GHashTable *data_maps; + + /* + * input trace class -> trace_ir_metadata_maps. + * input trace class: weak reference. Owned by an upstream component. + * trace_ir_metadata_maps: Owned by this structure. + */ + GHashTable *metadata_maps; + + char *debug_info_field_class_name; + + bt_self_component *self_comp; +}; + +struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, + const char *debug_info_field_name, bt_logging_level log_level); + +void trace_ir_maps_clear(struct trace_ir_maps *maps); + +void trace_ir_maps_destroy(struct trace_ir_maps *maps); + +struct trace_ir_data_maps *trace_ir_data_maps_create( + struct trace_ir_maps *ir_maps, + const bt_trace *in_trace); + +void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps); + +struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( + struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class); + +void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps); + +bt_stream_class *trace_ir_mapping_create_new_mapped_stream_class( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class); + +bt_stream_class *trace_ir_mapping_borrow_mapped_stream_class( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class); + +bt_stream *trace_ir_mapping_create_new_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +bt_stream *trace_ir_mapping_borrow_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +void trace_ir_mapping_remove_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +bt_event_class *trace_ir_mapping_create_new_mapped_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class); + +bt_event_class *trace_ir_mapping_borrow_mapped_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class); + +bt_packet *trace_ir_mapping_create_new_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet); + +bt_packet *trace_ir_mapping_borrow_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet); + +void trace_ir_mapping_remove_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet); + +static inline +struct trace_ir_data_maps *borrow_data_maps_from_input_trace( + struct trace_ir_maps *ir_maps, const bt_trace *in_trace) +{ + BT_ASSERT(ir_maps); + BT_ASSERT(in_trace); + + struct trace_ir_data_maps *d_maps = + static_cast(g_hash_table_lookup(ir_maps->data_maps, (gpointer) in_trace)); + if (!d_maps) { + d_maps = trace_ir_data_maps_create(ir_maps, in_trace); + g_hash_table_insert(ir_maps->data_maps, (gpointer) in_trace, d_maps); + } + + return d_maps; +} + +static inline +struct trace_ir_data_maps *borrow_data_maps_from_input_stream( + struct trace_ir_maps *ir_maps, const bt_stream *in_stream) +{ + BT_ASSERT(ir_maps); + BT_ASSERT(in_stream); + + return borrow_data_maps_from_input_trace(ir_maps, + bt_stream_borrow_trace_const(in_stream)); +} + +static inline +struct trace_ir_data_maps *borrow_data_maps_from_input_packet( + struct trace_ir_maps *ir_maps, const bt_packet *in_packet) +{ + BT_ASSERT(ir_maps); + BT_ASSERT(in_packet); + + return borrow_data_maps_from_input_stream(ir_maps, + bt_packet_borrow_stream_const(in_packet)); +} + +static inline +struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_trace_class( + struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class) +{ + BT_ASSERT(ir_maps); + BT_ASSERT(in_trace_class); + + struct trace_ir_metadata_maps *md_maps = + static_cast(g_hash_table_lookup(ir_maps->metadata_maps, + (gpointer) in_trace_class)); + if (!md_maps) { + md_maps = trace_ir_metadata_maps_create(ir_maps, in_trace_class); + g_hash_table_insert(ir_maps->metadata_maps, + (gpointer) in_trace_class, md_maps); + } + + return md_maps; +} + +static inline +struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_stream_class( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class) { + + BT_ASSERT(in_stream_class); + + return borrow_metadata_maps_from_input_trace_class(ir_maps, + bt_stream_class_borrow_trace_class_const(in_stream_class)); +} + +static inline +struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class) { + + BT_ASSERT(in_event_class); + + return borrow_metadata_maps_from_input_stream_class(ir_maps, + bt_event_class_borrow_stream_class_const(in_event_class)); +} + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_MAPPING_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c deleted file mode 100644 index 67f52845..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR metadata object copy - */ - -#define BT_COMP_LOG_SELF_COMP self_comp -#define BT_LOG_OUTPUT_LEVEL log_level -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-META-COPY" -#include "logging/comp-logging.h" - -#include -#include - -#include "common/assert.h" - -#include "trace-ir-metadata-copy.h" -#include "trace-ir-metadata-field-class-copy.h" -#include "utils.h" - -enum debug_info_trace_ir_mapping_status copy_trace_class_content( - struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class, - bt_trace_class *out_trace_class, - bt_logging_level log_level, bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - uint64_t sc_number, sc_idx; - - BT_COMP_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, out_trace_class); - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_trace_class_set_user_attributes(out_trace_class, - bt_trace_class_borrow_user_attributes_const(in_trace_class)); - - /* Use the same stream class ids as in the origin trace class. */ - bt_trace_class_set_assigns_automatic_stream_class_id(out_trace_class, - BT_FALSE); - - /* Copy stream classes contained in the trace class. */ - sc_number = bt_trace_class_get_stream_class_count(in_trace_class); - for (sc_idx = 0; sc_idx < sc_number; sc_idx++) { - bt_stream_class *out_stream_class; - const bt_stream_class *in_stream_class = - bt_trace_class_borrow_stream_class_by_index_const( - in_trace_class, sc_idx); - - out_stream_class = trace_ir_mapping_borrow_mapped_stream_class( - ir_maps, in_stream_class); - if (!out_stream_class) { - out_stream_class = trace_ir_mapping_create_new_mapped_stream_class( - ir_maps, in_stream_class); - if (!out_stream_class) { - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto end; - } - } - } - - BT_COMP_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, out_trace_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static -enum debug_info_trace_ir_mapping_status copy_clock_class_content( - const bt_clock_class *in_clock_class, - bt_clock_class *out_clock_class, bt_logging_level log_level, - bt_self_component *self_comp) -{ - enum debug_info_trace_ir_mapping_status status; - const char *clock_class_name, *clock_class_description; - int64_t seconds; - uint64_t cycles; - bt_uuid in_uuid; - - BT_COMP_LOGD("Copying content of clock class: in-cc-addr=%p, out-cc-addr=%p", - in_clock_class, out_clock_class); - - clock_class_name = bt_clock_class_get_name(in_clock_class); - - if (clock_class_name) { - enum bt_clock_class_set_name_status set_name_status = - bt_clock_class_set_name(out_clock_class, clock_class_name); - if (set_name_status != BT_CLOCK_CLASS_SET_NAME_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting clock class' name: " - "cc-addr=%p, name=%s", out_clock_class, - clock_class_name); - status = (int) set_name_status; - goto end; - } - } - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_clock_class_set_user_attributes(out_clock_class, - bt_clock_class_borrow_user_attributes_const(in_clock_class)); - - clock_class_description = bt_clock_class_get_description(in_clock_class); - - if (clock_class_description) { - enum bt_clock_class_set_description_status set_desc_status = - bt_clock_class_set_description(out_clock_class, clock_class_description); - if (set_desc_status!= BT_CLOCK_CLASS_SET_DESCRIPTION_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting clock class' description: " - "cc-addr=%p, cc-desc=%s", out_clock_class, - clock_class_description); - status = (int) set_desc_status; - goto end; - } - } - - in_uuid = bt_clock_class_get_uuid(in_clock_class); - if (in_uuid) { - bt_clock_class_set_uuid(out_clock_class, in_uuid); - } - - bt_clock_class_set_frequency(out_clock_class, - bt_clock_class_get_frequency(in_clock_class)); - bt_clock_class_set_precision(out_clock_class, - bt_clock_class_get_precision(in_clock_class)); - bt_clock_class_get_offset(in_clock_class, &seconds, &cycles); - bt_clock_class_set_offset(out_clock_class, seconds, cycles); - bt_clock_class_set_origin_is_unix_epoch(out_clock_class, - bt_clock_class_origin_is_unix_epoch(in_clock_class)); - - BT_COMP_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p", - in_clock_class, out_clock_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static -bt_clock_class *borrow_mapped_clock_class( - struct trace_ir_metadata_maps *md_maps, - const bt_clock_class *in_clock_class) -{ - BT_ASSERT_DBG(md_maps); - BT_ASSERT_DBG(in_clock_class); - - return g_hash_table_lookup(md_maps->clock_class_map, - (gpointer) in_clock_class); -} - -static -bt_clock_class *create_new_mapped_clock_class(bt_self_component *self_comp, - struct trace_ir_metadata_maps *md_maps, - const bt_clock_class *in_clock_class) -{ - enum debug_info_trace_ir_mapping_status status; - bt_clock_class *out_clock_class; - bt_logging_level log_level = md_maps->log_level; - - BT_COMP_LOGD("Creating new mapped clock class: in-cc-addr=%p", - in_clock_class); - - BT_ASSERT(md_maps); - BT_ASSERT(in_clock_class); - - BT_ASSERT(!borrow_mapped_clock_class(md_maps, in_clock_class)); - - out_clock_class = bt_clock_class_create(self_comp); - if (!out_clock_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create clock class"); - goto end; - } - /* If not, create a new one and add it to the mapping. */ - status = copy_clock_class_content(in_clock_class, out_clock_class, - log_level, self_comp); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy clock class"); - BT_CLOCK_CLASS_PUT_REF_AND_RESET(out_clock_class); - goto end; - } - - g_hash_table_insert(md_maps->clock_class_map, - (gpointer) in_clock_class, out_clock_class); - - BT_COMP_LOGD("Created new mapped clock class: in-cc-addr=%p, out-cc-addr=%p", - in_clock_class, out_clock_class); -end: - return out_clock_class; -} - -enum debug_info_trace_ir_mapping_status copy_stream_class_content( - struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class, - bt_stream_class *out_stream_class) -{ - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *md_maps; - const bt_clock_class *in_clock_class; - bt_clock_class *out_clock_class; - const bt_field_class *in_packet_context_fc, *in_common_context_fc; - bt_field_class *out_packet_context_fc, *out_common_context_fc; - const char *in_name; - uint64_t ec_number, ec_idx; - bt_logging_level log_level = ir_maps->log_level; - bt_self_component *self_comp = ir_maps->self_comp; - - BT_COMP_LOGD("Copying content of stream class: in-sc-addr=%p, out-sc-addr=%p", - in_stream_class, out_stream_class); - - md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class); - in_clock_class = bt_stream_class_borrow_default_clock_class_const( - in_stream_class); - - if (in_clock_class) { - enum bt_stream_class_set_default_clock_class_status set_def_cc_status; - /* Copy the clock class. */ - out_clock_class = borrow_mapped_clock_class(md_maps, - in_clock_class); - if (!out_clock_class) { - out_clock_class = create_new_mapped_clock_class( - ir_maps->self_comp, md_maps, in_clock_class); - if (!out_clock_class) { - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto end; - } - } - set_def_cc_status = bt_stream_class_set_default_clock_class( - out_stream_class, out_clock_class); - if (set_def_cc_status != BT_STREAM_CLASS_SET_DEFAULT_CLOCK_CLASS_STATUS_OK) { - status = (int) set_def_cc_status; - goto end; - } - } - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_stream_class_set_user_attributes(out_stream_class, - bt_stream_class_borrow_user_attributes_const(in_stream_class)); - - bt_stream_class_set_supports_packets( - out_stream_class, - bt_stream_class_supports_packets(in_stream_class), - bt_stream_class_packets_have_beginning_default_clock_snapshot( - in_stream_class), - bt_stream_class_packets_have_end_default_clock_snapshot( - in_stream_class)); - bt_stream_class_set_supports_discarded_events( - out_stream_class, - bt_stream_class_supports_discarded_events(in_stream_class), - bt_stream_class_discarded_events_have_default_clock_snapshots( - in_stream_class)); - bt_stream_class_set_supports_discarded_packets( - out_stream_class, - bt_stream_class_supports_discarded_packets(in_stream_class), - bt_stream_class_discarded_packets_have_default_clock_snapshots( - in_stream_class)); - - in_name = bt_stream_class_get_name(in_stream_class); - if (in_name) { - enum bt_stream_class_set_name_status set_name_status = - bt_stream_class_set_name(out_stream_class, in_name); - if (set_name_status != BT_STREAM_CLASS_SET_NAME_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error set stream class name: " - "out-sc-addr=%p, name=%s", out_stream_class, - in_name); - status = (int) set_name_status; - goto end; - } - } - - bt_stream_class_set_assigns_automatic_stream_id(out_stream_class, - BT_FALSE); - bt_stream_class_set_assigns_automatic_event_class_id(out_stream_class, - BT_FALSE); - - /* - * Add the input packet context field class to the context to - * resolution in the further steps. - */ - in_packet_context_fc = - bt_stream_class_borrow_packet_context_field_class_const( - in_stream_class); - md_maps->fc_resolving_ctx->packet_context = - in_packet_context_fc; - - if (in_packet_context_fc) { - enum bt_stream_class_set_field_class_status set_fc_status; - /* Copy packet context. */ - out_packet_context_fc = create_field_class_copy(md_maps, - in_packet_context_fc); - - status = copy_field_class_content(md_maps, in_packet_context_fc, - out_packet_context_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying stream class' packet context field class: " - "in-packet-ctx-fc-addr=%p, out-packet-ctx-fc-addr=%p", - in_packet_context_fc, out_packet_context_fc); - goto end; - } - - set_fc_status = bt_stream_class_set_packet_context_field_class( - out_stream_class, out_packet_context_fc); - if (set_fc_status != BT_STREAM_CLASS_SET_FIELD_CLASS_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting stream class' packet context field class: " - "out-sc-addr=%p, out-packet-ctx-fc-addr=%p", - out_stream_class, out_packet_context_fc); - status = (int) set_fc_status; - goto end; - } - } - - /* - * Add the input common context field class to the context to - * resolution in the further steps. - */ - in_common_context_fc = - bt_stream_class_borrow_event_common_context_field_class_const( - in_stream_class); - md_maps->fc_resolving_ctx->event_common_context = in_common_context_fc; - - if (in_common_context_fc) { - enum bt_stream_class_set_field_class_status set_fc_status; - /* Copy common context. */ - /* TODO: I find it a bit awkward to have this special function - * here to add the debug-info field class. I would like to - * abstract that.*/ - out_common_context_fc = create_field_class_copy(md_maps, - in_common_context_fc); - status = copy_event_common_context_field_class_content(md_maps, - ir_maps->debug_info_field_class_name, - in_common_context_fc, out_common_context_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying stream class' common context field class: " - "in-comm-ctx-fc-addr=%p, out-comm-ctx-fc-addr=%p", - in_common_context_fc, out_common_context_fc); - goto end; - } - - set_fc_status = bt_stream_class_set_event_common_context_field_class( - out_stream_class, out_common_context_fc); - if (set_fc_status != BT_STREAM_CLASS_SET_FIELD_CLASS_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting stream class' common context field class: " - "out-sc-addr=%p, out-comm-ctx-fc-addr=%p", - out_stream_class, out_common_context_fc); - status = (int) set_fc_status; - goto end; - } - } - - /* Copy event classes contained in the stream class. */ - ec_number = bt_stream_class_get_event_class_count(in_stream_class); - for (ec_idx = 0; ec_idx < ec_number; ec_idx++) { - bt_event_class *out_event_class; - const bt_event_class *in_event_class = - bt_stream_class_borrow_event_class_by_id_const( - in_stream_class, ec_idx); - out_event_class = trace_ir_mapping_borrow_mapped_event_class( - ir_maps, in_event_class); - if (!out_event_class) { - /* - * We don't need the new event_class yet. We simply - * want to create it and keep it in the map. - */ - out_event_class = trace_ir_mapping_create_new_mapped_event_class( - ir_maps, in_event_class); - if (!out_event_class) { - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto end; - } - } - } - - BT_COMP_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p", - in_stream_class, out_stream_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status copy_event_class_content( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class, - bt_event_class *out_event_class) -{ - enum debug_info_trace_ir_mapping_status status; - struct trace_ir_metadata_maps *md_maps; - const char *in_event_class_name, *in_emf_uri; - bt_property_availability prop_avail; - bt_event_class_log_level ec_log_level; - bt_field_class *out_specific_context_fc, *out_payload_fc; - const bt_field_class *in_event_specific_context, *in_event_payload; - bt_logging_level log_level = ir_maps->log_level; - bt_self_component *self_comp = ir_maps->self_comp; - - BT_COMP_LOGD("Copying content of event class: in-ec-addr=%p, out-ec-addr=%p", - in_event_class, out_event_class); - - /* Copy event class name. */ - in_event_class_name = bt_event_class_get_name(in_event_class); - if (in_event_class_name) { - enum bt_event_class_set_name_status set_name_status = - bt_event_class_set_name(out_event_class, in_event_class_name); - if (set_name_status != BT_EVENT_CLASS_SET_NAME_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error setting event class' name: ec-addr=%p, " - "name=%s", out_event_class, in_event_class_name); - status = (int) set_name_status; - goto end; - } - } - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_event_class_set_user_attributes(out_event_class, - bt_event_class_borrow_user_attributes_const(in_event_class)); - - /* Copy event class loglevel. */ - prop_avail = bt_event_class_get_log_level(in_event_class, - &ec_log_level); - if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) { - bt_event_class_set_log_level(out_event_class, ec_log_level); - } - - /* Copy event class emf uri. */ - in_emf_uri = bt_event_class_get_emf_uri(in_event_class); - if (in_emf_uri) { - enum bt_event_class_set_emf_uri_status set_emf_status = - bt_event_class_set_emf_uri(out_event_class, in_emf_uri); - if (set_emf_status != BT_EVENT_CLASS_SET_EMF_URI_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting event class' emf uri: " - "out-ec-addr=%p, emf-uri=\"%s\"", - out_event_class, in_emf_uri); - status = (int) set_emf_status; - goto end; - } - } - - md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, - in_event_class); - /* - * Add the input event class' specific ctx to te - * context. - */ - in_event_specific_context = - bt_event_class_borrow_specific_context_field_class_const( - in_event_class); - - md_maps->fc_resolving_ctx->event_specific_context = - in_event_specific_context; - - if (in_event_specific_context) { - enum bt_event_class_set_field_class_status set_fc_status; - /* Copy the specific context of this event class. */ - out_specific_context_fc = create_field_class_copy(md_maps, - in_event_specific_context); - - status = copy_field_class_content(md_maps, - in_event_specific_context, out_specific_context_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying event class' specific context field class:" - "in-spec-ctx-fc-addr=%p, out-spec-ctx-fc-addr=%p", - in_event_specific_context, out_specific_context_fc); - goto end; - } - /* - * Add the output specific context to the output event - * class. - */ - set_fc_status = bt_event_class_set_specific_context_field_class( - out_event_class, out_specific_context_fc); - if (set_fc_status != BT_EVENT_CLASS_SET_FIELD_CLASS_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error setting event class' specific context field class:" - "out-ec-addr=%p, out-spec-ctx-fc-addr=%p", - out_event_class, out_specific_context_fc); - status = (int) set_fc_status; - goto end; - } - } - - /* - * Add the input event class' payload field class to - * the context. - */ - in_event_payload = bt_event_class_borrow_payload_field_class_const( - in_event_class); - - md_maps->fc_resolving_ctx->event_payload = in_event_payload; - - if (in_event_payload) { - enum bt_event_class_set_field_class_status set_fc_status; - /* Copy the payload of this event class. */ - out_payload_fc = create_field_class_copy(md_maps, - in_event_payload); - status = copy_field_class_content(md_maps, in_event_payload, - out_payload_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying event class' specific context field class:" - "in-payload-fc-addr=%p, out-payload-fc-addr=%p", - in_event_payload, out_payload_fc); - goto end; - } - - /* Add the output payload to the output event class. */ - set_fc_status = bt_event_class_set_payload_field_class( - out_event_class, out_payload_fc); - if (set_fc_status != BT_EVENT_CLASS_SET_FIELD_CLASS_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error setting event class' payload field class: " - "out-ec-addr=%p, out-payload-fc-addr=%p", - out_event_class, out_payload_fc); - status = (int) set_fc_status; - goto end; - } - } - - BT_COMP_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p", - in_event_class, out_event_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -enum debug_info_trace_ir_mapping_status -copy_event_common_context_field_class_content( - struct trace_ir_metadata_maps *md_maps, - const char *debug_info_fc_name, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - enum debug_info_trace_ir_mapping_status status; - bt_field_class *debug_field_class = NULL, *bin_field_class = NULL, - *func_field_class = NULL, *src_field_class = NULL; - bt_logging_level log_level = md_maps->log_level; - bt_self_component *self_comp = md_maps->self_comp; - - BT_COMP_LOGD("Copying content of event common context field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - /* Copy the content of the input common context. */ - status = copy_field_class_content(md_maps, in_field_class, out_field_class); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying content of event common context field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, - out_field_class); - goto error; - } - - /* - * If this event common context has the necessary fields to compute the - * debug information append the debug-info field class to the event - * common context. - */ - if (is_event_common_ctx_dbg_info_compatible(in_field_class, debug_info_fc_name)) { - enum bt_field_class_structure_append_member_status append_member_status; - /* - * The struct field and 3 sub-fields are not stored in the - * field class map because they don't have input equivalent. - * We need to put our reference each of these field classes - * once they are added to their respective containing field - * classes. - */ - debug_field_class = bt_field_class_structure_create( - md_maps->output_trace_class); - if (!debug_field_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to create debug_info structure."); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto error; - } - - bin_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!bin_field_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to create string for field=\"bin\"."); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto error; - } - - func_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!func_field_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to create string for field=\"func\"."); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto error; - } - - src_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!src_field_class) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to create string for field=\"src\"."); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto error; - } - - append_member_status = bt_field_class_structure_append_member( - debug_field_class, "bin", bin_field_class); - if (append_member_status != - BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to add a field to debug_info struct: " - "field=\"bin\"."); - status = (int) append_member_status; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class); - - append_member_status = bt_field_class_structure_append_member( - debug_field_class, "func", func_field_class); - if (append_member_status != - BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to add a field to debug_info struct: " - "field=\"func\"."); - status = (int) append_member_status; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class); - - append_member_status = bt_field_class_structure_append_member( - debug_field_class, "src", src_field_class); - if (append_member_status != - BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to add a field to debug_info struct: " - "field=\"src\"."); - status = (int) append_member_status; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class); - - /*Add the filled debug-info field class to the common context. */ - append_member_status = bt_field_class_structure_append_member( - out_field_class, debug_info_fc_name, debug_field_class); - if (append_member_status != - BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Failed to add debug_info field to event common context."); - status = (int) append_member_status; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class); - } - BT_COMP_LOGD("Copied content of event common context field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; - goto end; - -error: - if (debug_field_class) { - bt_field_class_put_ref(debug_field_class); - } - if (bin_field_class) { - bt_field_class_put_ref(bin_field_class); - } - if (func_field_class) { - bt_field_class_put_ref(func_field_class); - } - if (src_field_class) { - bt_field_class_put_ref(src_field_class); - } -end: - return status; -} - -bt_field_class *create_field_class_copy(struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class) -{ - return create_field_class_copy_internal(md_maps, in_field_class); -} - -enum debug_info_trace_ir_mapping_status copy_field_class_content( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - return copy_field_class_content_internal(md_maps, in_field_class, - out_field_class); -} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.cpp b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.cpp new file mode 100644 index 00000000..c8f043c5 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.cpp @@ -0,0 +1,711 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR metadata object copy + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP self_comp +#define BT_LOG_OUTPUT_LEVEL log_level +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-META-COPY" +#include "logging/comp-logging.h" + +#include +#include + +#include "common/assert.h" + +#include "trace-ir-metadata-copy.hpp" +#include "trace-ir-metadata-field-class-copy.hpp" +#include "utils.hpp" + +enum debug_info_trace_ir_mapping_status copy_trace_class_content( + struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class, + bt_trace_class *out_trace_class, + bt_logging_level log_level, bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + uint64_t sc_number, sc_idx; + + BT_COMP_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, out_trace_class); + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_trace_class_set_user_attributes(out_trace_class, + bt_trace_class_borrow_user_attributes_const(in_trace_class)); + + /* Use the same stream class ids as in the origin trace class. */ + bt_trace_class_set_assigns_automatic_stream_class_id(out_trace_class, + BT_FALSE); + + /* Copy stream classes contained in the trace class. */ + sc_number = bt_trace_class_get_stream_class_count(in_trace_class); + for (sc_idx = 0; sc_idx < sc_number; sc_idx++) { + bt_stream_class *out_stream_class; + const bt_stream_class *in_stream_class = + bt_trace_class_borrow_stream_class_by_index_const( + in_trace_class, sc_idx); + + out_stream_class = trace_ir_mapping_borrow_mapped_stream_class( + ir_maps, in_stream_class); + if (!out_stream_class) { + out_stream_class = trace_ir_mapping_create_new_mapped_stream_class( + ir_maps, in_stream_class); + if (!out_stream_class) { + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto end; + } + } + } + + BT_COMP_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, out_trace_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static +enum debug_info_trace_ir_mapping_status copy_clock_class_content( + const bt_clock_class *in_clock_class, + bt_clock_class *out_clock_class, bt_logging_level log_level, + bt_self_component *self_comp) +{ + enum debug_info_trace_ir_mapping_status status; + const char *clock_class_name, *clock_class_description; + int64_t seconds; + uint64_t cycles; + bt_uuid in_uuid; + + BT_COMP_LOGD("Copying content of clock class: in-cc-addr=%p, out-cc-addr=%p", + in_clock_class, out_clock_class); + + clock_class_name = bt_clock_class_get_name(in_clock_class); + + if (clock_class_name) { + enum bt_clock_class_set_name_status set_name_status = + bt_clock_class_set_name(out_clock_class, clock_class_name); + if (set_name_status != BT_CLOCK_CLASS_SET_NAME_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting clock class' name: " + "cc-addr=%p, name=%s", out_clock_class, + clock_class_name); + status = static_cast(set_name_status); + goto end; + } + } + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_clock_class_set_user_attributes(out_clock_class, + bt_clock_class_borrow_user_attributes_const(in_clock_class)); + + clock_class_description = bt_clock_class_get_description(in_clock_class); + + if (clock_class_description) { + enum bt_clock_class_set_description_status set_desc_status = + bt_clock_class_set_description(out_clock_class, clock_class_description); + if (set_desc_status!= BT_CLOCK_CLASS_SET_DESCRIPTION_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting clock class' description: " + "cc-addr=%p, cc-desc=%s", out_clock_class, + clock_class_description); + status = static_cast(set_desc_status); + goto end; + } + } + + in_uuid = bt_clock_class_get_uuid(in_clock_class); + if (in_uuid) { + bt_clock_class_set_uuid(out_clock_class, in_uuid); + } + + bt_clock_class_set_frequency(out_clock_class, + bt_clock_class_get_frequency(in_clock_class)); + bt_clock_class_set_precision(out_clock_class, + bt_clock_class_get_precision(in_clock_class)); + bt_clock_class_get_offset(in_clock_class, &seconds, &cycles); + bt_clock_class_set_offset(out_clock_class, seconds, cycles); + bt_clock_class_set_origin_is_unix_epoch(out_clock_class, + bt_clock_class_origin_is_unix_epoch(in_clock_class)); + + BT_COMP_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p", + in_clock_class, out_clock_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static +bt_clock_class *borrow_mapped_clock_class( + struct trace_ir_metadata_maps *md_maps, + const bt_clock_class *in_clock_class) +{ + BT_ASSERT_DBG(md_maps); + BT_ASSERT_DBG(in_clock_class); + + return static_cast(g_hash_table_lookup(md_maps->clock_class_map, + (gpointer) in_clock_class)); +} + +static +bt_clock_class *create_new_mapped_clock_class(bt_self_component *self_comp, + struct trace_ir_metadata_maps *md_maps, + const bt_clock_class *in_clock_class) +{ + enum debug_info_trace_ir_mapping_status status; + bt_clock_class *out_clock_class; + bt_logging_level log_level = md_maps->log_level; + + BT_COMP_LOGD("Creating new mapped clock class: in-cc-addr=%p", + in_clock_class); + + BT_ASSERT(md_maps); + BT_ASSERT(in_clock_class); + + BT_ASSERT(!borrow_mapped_clock_class(md_maps, in_clock_class)); + + out_clock_class = bt_clock_class_create(self_comp); + if (!out_clock_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create clock class"); + goto end; + } + /* If not, create a new one and add it to the mapping. */ + status = copy_clock_class_content(in_clock_class, out_clock_class, + log_level, self_comp); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy clock class"); + BT_CLOCK_CLASS_PUT_REF_AND_RESET(out_clock_class); + goto end; + } + + g_hash_table_insert(md_maps->clock_class_map, + (gpointer) in_clock_class, out_clock_class); + + BT_COMP_LOGD("Created new mapped clock class: in-cc-addr=%p, out-cc-addr=%p", + in_clock_class, out_clock_class); +end: + return out_clock_class; +} + +enum debug_info_trace_ir_mapping_status copy_stream_class_content( + struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class, + bt_stream_class *out_stream_class) +{ + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *md_maps; + const bt_clock_class *in_clock_class; + bt_clock_class *out_clock_class; + const bt_field_class *in_packet_context_fc, *in_common_context_fc; + bt_field_class *out_packet_context_fc, *out_common_context_fc; + const char *in_name; + uint64_t ec_number, ec_idx; + bt_logging_level log_level = ir_maps->log_level; + bt_self_component *self_comp = ir_maps->self_comp; + + BT_COMP_LOGD("Copying content of stream class: in-sc-addr=%p, out-sc-addr=%p", + in_stream_class, out_stream_class); + + md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class); + in_clock_class = bt_stream_class_borrow_default_clock_class_const( + in_stream_class); + + if (in_clock_class) { + enum bt_stream_class_set_default_clock_class_status set_def_cc_status; + /* Copy the clock class. */ + out_clock_class = borrow_mapped_clock_class(md_maps, + in_clock_class); + if (!out_clock_class) { + out_clock_class = create_new_mapped_clock_class( + ir_maps->self_comp, md_maps, in_clock_class); + if (!out_clock_class) { + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto end; + } + } + set_def_cc_status = bt_stream_class_set_default_clock_class( + out_stream_class, out_clock_class); + if (set_def_cc_status != BT_STREAM_CLASS_SET_DEFAULT_CLOCK_CLASS_STATUS_OK) { + status = static_cast(set_def_cc_status); + goto end; + } + } + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_stream_class_set_user_attributes(out_stream_class, + bt_stream_class_borrow_user_attributes_const(in_stream_class)); + + bt_stream_class_set_supports_packets( + out_stream_class, + bt_stream_class_supports_packets(in_stream_class), + bt_stream_class_packets_have_beginning_default_clock_snapshot( + in_stream_class), + bt_stream_class_packets_have_end_default_clock_snapshot( + in_stream_class)); + bt_stream_class_set_supports_discarded_events( + out_stream_class, + bt_stream_class_supports_discarded_events(in_stream_class), + bt_stream_class_discarded_events_have_default_clock_snapshots( + in_stream_class)); + bt_stream_class_set_supports_discarded_packets( + out_stream_class, + bt_stream_class_supports_discarded_packets(in_stream_class), + bt_stream_class_discarded_packets_have_default_clock_snapshots( + in_stream_class)); + + in_name = bt_stream_class_get_name(in_stream_class); + if (in_name) { + enum bt_stream_class_set_name_status set_name_status = + bt_stream_class_set_name(out_stream_class, in_name); + if (set_name_status != BT_STREAM_CLASS_SET_NAME_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error set stream class name: " + "out-sc-addr=%p, name=%s", out_stream_class, + in_name); + status = static_cast(set_name_status); + goto end; + } + } + + bt_stream_class_set_assigns_automatic_stream_id(out_stream_class, + BT_FALSE); + bt_stream_class_set_assigns_automatic_event_class_id(out_stream_class, + BT_FALSE); + + /* + * Add the input packet context field class to the context to + * resolution in the further steps. + */ + in_packet_context_fc = + bt_stream_class_borrow_packet_context_field_class_const( + in_stream_class); + md_maps->fc_resolving_ctx->packet_context = + in_packet_context_fc; + + if (in_packet_context_fc) { + enum bt_stream_class_set_field_class_status set_fc_status; + /* Copy packet context. */ + out_packet_context_fc = create_field_class_copy(md_maps, + in_packet_context_fc); + + status = copy_field_class_content(md_maps, in_packet_context_fc, + out_packet_context_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying stream class' packet context field class: " + "in-packet-ctx-fc-addr=%p, out-packet-ctx-fc-addr=%p", + in_packet_context_fc, out_packet_context_fc); + goto end; + } + + set_fc_status = bt_stream_class_set_packet_context_field_class( + out_stream_class, out_packet_context_fc); + if (set_fc_status != BT_STREAM_CLASS_SET_FIELD_CLASS_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting stream class' packet context field class: " + "out-sc-addr=%p, out-packet-ctx-fc-addr=%p", + out_stream_class, out_packet_context_fc); + status = static_cast(set_fc_status); + goto end; + } + } + + /* + * Add the input common context field class to the context to + * resolution in the further steps. + */ + in_common_context_fc = + bt_stream_class_borrow_event_common_context_field_class_const( + in_stream_class); + md_maps->fc_resolving_ctx->event_common_context = in_common_context_fc; + + if (in_common_context_fc) { + enum bt_stream_class_set_field_class_status set_fc_status; + /* Copy common context. */ + /* TODO: I find it a bit awkward to have this special function + * here to add the debug-info field class. I would like to + * abstract that.*/ + out_common_context_fc = create_field_class_copy(md_maps, + in_common_context_fc); + status = copy_event_common_context_field_class_content(md_maps, + ir_maps->debug_info_field_class_name, + in_common_context_fc, out_common_context_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying stream class' common context field class: " + "in-comm-ctx-fc-addr=%p, out-comm-ctx-fc-addr=%p", + in_common_context_fc, out_common_context_fc); + goto end; + } + + set_fc_status = bt_stream_class_set_event_common_context_field_class( + out_stream_class, out_common_context_fc); + if (set_fc_status != BT_STREAM_CLASS_SET_FIELD_CLASS_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting stream class' common context field class: " + "out-sc-addr=%p, out-comm-ctx-fc-addr=%p", + out_stream_class, out_common_context_fc); + status = static_cast(set_fc_status); + goto end; + } + } + + /* Copy event classes contained in the stream class. */ + ec_number = bt_stream_class_get_event_class_count(in_stream_class); + for (ec_idx = 0; ec_idx < ec_number; ec_idx++) { + bt_event_class *out_event_class; + const bt_event_class *in_event_class = + bt_stream_class_borrow_event_class_by_id_const( + in_stream_class, ec_idx); + out_event_class = trace_ir_mapping_borrow_mapped_event_class( + ir_maps, in_event_class); + if (!out_event_class) { + /* + * We don't need the new event_class yet. We simply + * want to create it and keep it in the map. + */ + out_event_class = trace_ir_mapping_create_new_mapped_event_class( + ir_maps, in_event_class); + if (!out_event_class) { + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto end; + } + } + } + + BT_COMP_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p", + in_stream_class, out_stream_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status copy_event_class_content( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class, + bt_event_class *out_event_class) +{ + enum debug_info_trace_ir_mapping_status status; + struct trace_ir_metadata_maps *md_maps; + const char *in_event_class_name, *in_emf_uri; + bt_property_availability prop_avail; + bt_event_class_log_level ec_log_level; + bt_field_class *out_specific_context_fc, *out_payload_fc; + const bt_field_class *in_event_specific_context, *in_event_payload; + bt_logging_level log_level = ir_maps->log_level; + bt_self_component *self_comp = ir_maps->self_comp; + + BT_COMP_LOGD("Copying content of event class: in-ec-addr=%p, out-ec-addr=%p", + in_event_class, out_event_class); + + /* Copy event class name. */ + in_event_class_name = bt_event_class_get_name(in_event_class); + if (in_event_class_name) { + enum bt_event_class_set_name_status set_name_status = + bt_event_class_set_name(out_event_class, in_event_class_name); + if (set_name_status != BT_EVENT_CLASS_SET_NAME_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error setting event class' name: ec-addr=%p, " + "name=%s", out_event_class, in_event_class_name); + status = static_cast(set_name_status); + goto end; + } + } + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_event_class_set_user_attributes(out_event_class, + bt_event_class_borrow_user_attributes_const(in_event_class)); + + /* Copy event class loglevel. */ + prop_avail = bt_event_class_get_log_level(in_event_class, + &ec_log_level); + if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) { + bt_event_class_set_log_level(out_event_class, ec_log_level); + } + + /* Copy event class emf uri. */ + in_emf_uri = bt_event_class_get_emf_uri(in_event_class); + if (in_emf_uri) { + enum bt_event_class_set_emf_uri_status set_emf_status = + bt_event_class_set_emf_uri(out_event_class, in_emf_uri); + if (set_emf_status != BT_EVENT_CLASS_SET_EMF_URI_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting event class' emf uri: " + "out-ec-addr=%p, emf-uri=\"%s\"", + out_event_class, in_emf_uri); + status = static_cast(set_emf_status); + goto end; + } + } + + md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, + in_event_class); + /* + * Add the input event class' specific ctx to te + * context. + */ + in_event_specific_context = + bt_event_class_borrow_specific_context_field_class_const( + in_event_class); + + md_maps->fc_resolving_ctx->event_specific_context = + in_event_specific_context; + + if (in_event_specific_context) { + enum bt_event_class_set_field_class_status set_fc_status; + /* Copy the specific context of this event class. */ + out_specific_context_fc = create_field_class_copy(md_maps, + in_event_specific_context); + + status = copy_field_class_content(md_maps, + in_event_specific_context, out_specific_context_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying event class' specific context field class:" + "in-spec-ctx-fc-addr=%p, out-spec-ctx-fc-addr=%p", + in_event_specific_context, out_specific_context_fc); + goto end; + } + /* + * Add the output specific context to the output event + * class. + */ + set_fc_status = bt_event_class_set_specific_context_field_class( + out_event_class, out_specific_context_fc); + if (set_fc_status != BT_EVENT_CLASS_SET_FIELD_CLASS_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error setting event class' specific context field class:" + "out-ec-addr=%p, out-spec-ctx-fc-addr=%p", + out_event_class, out_specific_context_fc); + status = static_cast(set_fc_status); + goto end; + } + } + + /* + * Add the input event class' payload field class to + * the context. + */ + in_event_payload = bt_event_class_borrow_payload_field_class_const( + in_event_class); + + md_maps->fc_resolving_ctx->event_payload = in_event_payload; + + if (in_event_payload) { + enum bt_event_class_set_field_class_status set_fc_status; + /* Copy the payload of this event class. */ + out_payload_fc = create_field_class_copy(md_maps, + in_event_payload); + status = copy_field_class_content(md_maps, in_event_payload, + out_payload_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying event class' specific context field class:" + "in-payload-fc-addr=%p, out-payload-fc-addr=%p", + in_event_payload, out_payload_fc); + goto end; + } + + /* Add the output payload to the output event class. */ + set_fc_status = bt_event_class_set_payload_field_class( + out_event_class, out_payload_fc); + if (set_fc_status != BT_EVENT_CLASS_SET_FIELD_CLASS_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error setting event class' payload field class: " + "out-ec-addr=%p, out-payload-fc-addr=%p", + out_event_class, out_payload_fc); + status = static_cast(set_fc_status); + goto end; + } + } + + BT_COMP_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p", + in_event_class, out_event_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +enum debug_info_trace_ir_mapping_status +copy_event_common_context_field_class_content( + struct trace_ir_metadata_maps *md_maps, + const char *debug_info_fc_name, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + enum debug_info_trace_ir_mapping_status status; + bt_field_class *debug_field_class = NULL, *bin_field_class = NULL, + *func_field_class = NULL, *src_field_class = NULL; + bt_logging_level log_level = md_maps->log_level; + bt_self_component *self_comp = md_maps->self_comp; + + BT_COMP_LOGD("Copying content of event common context field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + /* Copy the content of the input common context. */ + status = copy_field_class_content(md_maps, in_field_class, out_field_class); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying content of event common context field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, + out_field_class); + goto error; + } + + /* + * If this event common context has the necessary fields to compute the + * debug information append the debug-info field class to the event + * common context. + */ + if (is_event_common_ctx_dbg_info_compatible(in_field_class, debug_info_fc_name)) { + enum bt_field_class_structure_append_member_status append_member_status; + /* + * The struct field and 3 sub-fields are not stored in the + * field class map because they don't have input equivalent. + * We need to put our reference each of these field classes + * once they are added to their respective containing field + * classes. + */ + debug_field_class = bt_field_class_structure_create( + md_maps->output_trace_class); + if (!debug_field_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to create debug_info structure."); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto error; + } + + bin_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!bin_field_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to create string for field=\"bin\"."); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto error; + } + + func_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!func_field_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to create string for field=\"func\"."); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto error; + } + + src_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!src_field_class) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to create string for field=\"src\"."); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto error; + } + + append_member_status = bt_field_class_structure_append_member( + debug_field_class, "bin", bin_field_class); + if (append_member_status != + BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to add a field to debug_info struct: " + "field=\"bin\"."); + status = static_cast(append_member_status); + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class); + + append_member_status = bt_field_class_structure_append_member( + debug_field_class, "func", func_field_class); + if (append_member_status != + BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to add a field to debug_info struct: " + "field=\"func\"."); + status = static_cast(append_member_status); + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class); + + append_member_status = bt_field_class_structure_append_member( + debug_field_class, "src", src_field_class); + if (append_member_status != + BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to add a field to debug_info struct: " + "field=\"src\"."); + status = static_cast(append_member_status); + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class); + + /*Add the filled debug-info field class to the common context. */ + append_member_status = bt_field_class_structure_append_member( + out_field_class, debug_info_fc_name, debug_field_class); + if (append_member_status != + BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Failed to add debug_info field to event common context."); + status = static_cast(append_member_status); + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class); + } + BT_COMP_LOGD("Copied content of event common context field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; + goto end; + +error: + if (debug_field_class) { + bt_field_class_put_ref(debug_field_class); + } + if (bin_field_class) { + bt_field_class_put_ref(bin_field_class); + } + if (func_field_class) { + bt_field_class_put_ref(func_field_class); + } + if (src_field_class) { + bt_field_class_put_ref(src_field_class); + } +end: + return status; +} + +bt_field_class *create_field_class_copy(struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class) +{ + return create_field_class_copy_internal(md_maps, in_field_class); +} + +enum debug_info_trace_ir_mapping_status copy_field_class_content( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + return copy_field_class_content_internal(md_maps, in_field_class, + out_field_class); +} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h deleted file mode 100644 index 06c99035..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR metadata object copy - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_H - -#include -#include "common/macros.h" -#include "trace-ir-mapping.h" - -enum debug_info_trace_ir_mapping_status copy_trace_class_content( - struct trace_ir_maps *trace_ir_maps, - const bt_trace_class *in_trace_class, - bt_trace_class *out_trace_class, - bt_logging_level log_level, - bt_self_component *self_comp); - -enum debug_info_trace_ir_mapping_status copy_stream_class_content( - struct trace_ir_maps *trace_ir_maps, - const bt_stream_class *in_stream_class, - bt_stream_class *out_stream_class); - -enum debug_info_trace_ir_mapping_status copy_event_class_content( - struct trace_ir_maps *trace_ir_maps, - const bt_event_class *in_event_class, - bt_event_class *out_event_class); - -enum debug_info_trace_ir_mapping_status copy_field_class_content( - struct trace_ir_metadata_maps *trace_ir_metadata_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class); - -enum debug_info_trace_ir_mapping_status copy_event_common_context_field_class_content( - struct trace_ir_metadata_maps *trace_ir_metadata_maps, - const char *debug_info_field_class_name, - const bt_field_class *in_field_class, - bt_field_class *out_field_class); - -bt_field_class *create_field_class_copy( - struct trace_ir_metadata_maps *trace_ir_metadata_maps, - const bt_field_class *in_field_class); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_H */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.hpp b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.hpp new file mode 100644 index 00000000..7f704b44 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.hpp @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR metadata object copy + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_HPP + +#include +#include "common/macros.h" +#include "trace-ir-mapping.hpp" + +enum debug_info_trace_ir_mapping_status copy_trace_class_content( + struct trace_ir_maps *trace_ir_maps, + const bt_trace_class *in_trace_class, + bt_trace_class *out_trace_class, + bt_logging_level log_level, + bt_self_component *self_comp); + +enum debug_info_trace_ir_mapping_status copy_stream_class_content( + struct trace_ir_maps *trace_ir_maps, + const bt_stream_class *in_stream_class, + bt_stream_class *out_stream_class); + +enum debug_info_trace_ir_mapping_status copy_event_class_content( + struct trace_ir_maps *trace_ir_maps, + const bt_event_class *in_event_class, + bt_event_class *out_event_class); + +enum debug_info_trace_ir_mapping_status copy_field_class_content( + struct trace_ir_metadata_maps *trace_ir_metadata_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class); + +enum debug_info_trace_ir_mapping_status copy_event_common_context_field_class_content( + struct trace_ir_metadata_maps *trace_ir_metadata_maps, + const char *debug_info_field_class_name, + const bt_field_class *in_field_class, + bt_field_class *out_field_class); + +bt_field_class *create_field_class_copy( + struct trace_ir_metadata_maps *trace_ir_metadata_maps, + const bt_field_class *in_field_class); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_COPY_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c deleted file mode 100644 index 7dbb262c..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR field copy - */ - -#define BT_COMP_LOG_SELF_COMP (md_maps->self_comp) -#define BT_LOG_OUTPUT_LEVEL (md_maps->log_level) -#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-META-FC-COPY" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include "common/common.h" -#include "compat/compiler.h" -#include - -#include "trace-ir-metadata-copy.h" -#include "trace-ir-metadata-field-class-copy.h" - -/* - * This function walks through the nested structures field class to resolve a - * field path object. A field path is made of indexes inside possibly nested - * structures ultimately leading to a field class. - */ -static -const bt_field_class *walk_field_path(struct trace_ir_metadata_maps *md_maps, - const bt_field_path *fp, const bt_field_class *fc) -{ - uint64_t i, fp_item_count; - const bt_field_class *curr_fc; - - BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE); - BT_COMP_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p", - fp, fc); - - fp_item_count = bt_field_path_get_item_count(fp); - curr_fc = fc; - for (i = 0; i < fp_item_count; i++) { - bt_field_class_type fc_type = bt_field_class_get_type(curr_fc); - const bt_field_path_item *fp_item = - bt_field_path_borrow_item_by_index_const(fp, i); - - if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { - const bt_field_class_structure_member *member; - - BT_ASSERT(bt_field_path_item_get_type(fp_item) == - BT_FIELD_PATH_ITEM_TYPE_INDEX); - member = bt_field_class_structure_borrow_member_by_index_const( - curr_fc, - bt_field_path_item_index_get_index(fp_item)); - curr_fc = bt_field_class_structure_member_borrow_field_class_const( - member); - } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_OPTION)) { - BT_ASSERT(bt_field_path_item_get_type(fp_item) == - BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT); - curr_fc = bt_field_class_option_borrow_field_class_const( - curr_fc); - - } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) { - const bt_field_class_variant_option *option; - - BT_ASSERT(bt_field_path_item_get_type(fp_item) == - BT_FIELD_PATH_ITEM_TYPE_INDEX); - option = bt_field_class_variant_borrow_option_by_index_const( - curr_fc, - bt_field_path_item_index_get_index(fp_item)); - curr_fc = bt_field_class_variant_option_borrow_field_class_const( - option); - break; - } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) { - BT_ASSERT(bt_field_path_item_get_type(fp_item) == - BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT); - curr_fc = bt_field_class_array_borrow_element_field_class_const( - curr_fc); - break; - } else { - bt_common_abort(); - } - } - - return curr_fc; -} - -static -const bt_field_class *resolve_field_path_to_field_class(const bt_field_path *fp, - struct trace_ir_metadata_maps *md_maps) -{ - struct field_class_resolving_context *fc_resolving_ctx; - const bt_field_class *fc; - bt_field_path_scope fp_scope; - - BT_COMP_LOGD("Resolving field path: fp-addr=%p", fp); - - fc_resolving_ctx = md_maps->fc_resolving_ctx; - fp_scope = bt_field_path_get_root_scope(fp); - - switch (fp_scope) { - case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT: - fc = walk_field_path(md_maps, fp, - fc_resolving_ctx->packet_context); - break; - case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT: - fc = walk_field_path(md_maps, fp, - fc_resolving_ctx->event_common_context); - break; - case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT: - fc = walk_field_path(md_maps, fp, - fc_resolving_ctx->event_specific_context); - break; - case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD: - fc = walk_field_path(md_maps, fp, - fc_resolving_ctx->event_payload); - break; - default: - bt_common_abort(); - } - - return fc; -} - -static inline -void field_class_integer_set_props(const bt_field_class *input_fc, - bt_field_class *output_fc) -{ - bt_field_class_integer_set_preferred_display_base(output_fc, - bt_field_class_integer_get_preferred_display_base(input_fc)); - bt_field_class_integer_set_field_value_range(output_fc, - bt_field_class_integer_get_field_value_range(input_fc)); -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_bool_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of boolean field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - /* - * There is no content to copy. Keep this function call anyway for - * logging purposes. - */ - BT_COMP_LOGD("Copied content of boolean field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_bit_array_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of bit array field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - /* - * There is no content to copy. Keep this function call anyway for - * logging purposes. - */ - BT_COMP_LOGD("Copied content of bit array field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_unsigned_integer_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of unsigned integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - field_class_integer_set_props(in_field_class, out_field_class); - - BT_COMP_LOGD("Copied content of unsigned integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_signed_integer_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of signed integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - field_class_integer_set_props(in_field_class, out_field_class); - - BT_COMP_LOGD("Copied content of signed integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static -enum debug_info_trace_ir_mapping_status field_class_unsigned_enumeration_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - enum debug_info_trace_ir_mapping_status status; - uint64_t i, enum_mapping_count; - - BT_COMP_LOGD("Copying content of unsigned enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - /* Copy properties of the inner integer. */ - field_class_integer_set_props(in_field_class, out_field_class); - - /* Copy all enumeration entries. */ - enum_mapping_count = bt_field_class_enumeration_get_mapping_count( - in_field_class); - for (i = 0; i < enum_mapping_count; i++) { - const char *label; - const bt_integer_range_set_unsigned *range_set; - const bt_field_class_enumeration_unsigned_mapping *u_mapping; - const bt_field_class_enumeration_mapping *mapping; - enum bt_field_class_enumeration_add_mapping_status add_mapping_status; - - u_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const( - in_field_class, i); - mapping = bt_field_class_enumeration_unsigned_mapping_as_mapping_const( - u_mapping); - label = bt_field_class_enumeration_mapping_get_label(mapping); - range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const( - u_mapping); - add_mapping_status = bt_field_class_enumeration_unsigned_add_mapping( - out_field_class, label, range_set); - if (add_mapping_status != BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_OK) { - status = (int) add_mapping_status; - goto end; - } - } - - BT_COMP_LOGD("Copied content of unsigned enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_signed_enumeration_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - enum debug_info_trace_ir_mapping_status status; - uint64_t i, enum_mapping_count; - - BT_COMP_LOGD("Copying content of signed enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - /* Copy properties of the inner integer. */ - field_class_integer_set_props(in_field_class, out_field_class); - - /* Copy all enumeration entries. */ - enum_mapping_count = - bt_field_class_enumeration_get_mapping_count(in_field_class); - for (i = 0; i < enum_mapping_count; i++) { - const char *label; - const bt_integer_range_set_signed *range_set; - const bt_field_class_enumeration_signed_mapping *s_mapping; - const bt_field_class_enumeration_mapping *mapping; - enum bt_field_class_enumeration_add_mapping_status add_mapping_status; - - s_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const( - in_field_class, i); - mapping = bt_field_class_enumeration_signed_mapping_as_mapping_const( - s_mapping); - label = bt_field_class_enumeration_mapping_get_label(mapping); - range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const( - s_mapping); - add_mapping_status = bt_field_class_enumeration_signed_add_mapping( - out_field_class, label, range_set); - if (add_mapping_status != BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_OK) { - status = (int) add_mapping_status; - goto end; - } - } - - BT_COMP_LOGD("Copied content of signed enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_single_precision_real_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of single-precision real field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - BT_COMP_LOGD("Copied content single-precision real field class:" - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_double_precision_real_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of double-precision real field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - BT_COMP_LOGD("Copied content double-precision real field class:" - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_structure_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - bt_self_component *self_comp = md_maps->self_comp; - uint64_t i, struct_member_count; - enum debug_info_trace_ir_mapping_status status; - - BT_COMP_LOGD("Copying content of structure field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - /* Get the number of member in that struct. */ - struct_member_count = - bt_field_class_structure_get_member_count(in_field_class); - - /* Iterate over all the members of the struct. */ - for (i = 0; i < struct_member_count; i++) { - enum bt_field_class_structure_append_member_status append_member_status; - const bt_field_class_structure_member *in_member; - bt_field_class_structure_member *out_member; - const char *member_name; - const bt_field_class *in_member_fc; - bt_field_class *out_member_fc; - - in_member = bt_field_class_structure_borrow_member_by_index_const( - in_field_class, i); - in_member_fc = bt_field_class_structure_member_borrow_field_class_const( - in_member); - member_name = bt_field_class_structure_member_get_name(in_member); - BT_COMP_LOGD("Copying structure field class's member: " - "index=%" PRId64 ", member-fc-addr=%p, member-name=\"%s\"", - i, in_member_fc, member_name); - - out_member_fc = create_field_class_copy(md_maps, in_member_fc); - if (!out_member_fc) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy structure field class's member: " - "index=%" PRId64 ", in-member-fc-addr=%p, " - "member-name=\"%s\"", i, in_member_fc, - member_name); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto end; - } - - status = copy_field_class_content(md_maps, in_member_fc, - out_member_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy content of structure field class's member: " - "index=%" PRId64 ", in-member-fc-addr=%p, " - "member-name=\"%s\"", i, in_member_fc, - member_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_fc); - goto end; - } - - append_member_status = bt_field_class_structure_append_member(out_field_class, - member_name, out_member_fc); - if (append_member_status != - BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append structure field class's field: " - "index=%" PRId64 ", field-fc-addr=%p, " - "field-name=\"%s\"", i, in_member_fc, - member_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_fc); - status = (int) append_member_status; - goto end; - } - - out_member = bt_field_class_structure_borrow_member_by_index( - out_field_class, i); - BT_ASSERT(out_member); - - /* - * Safe to use the same value object because it's frozen - * at this point. - */ - bt_field_class_structure_member_set_user_attributes( - out_member, - bt_field_class_structure_member_borrow_user_attributes_const( - in_member)); - } - - BT_COMP_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p", - in_field_class, out_field_class); - - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_variant_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - bt_self_component *self_comp = md_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - bt_field_class *out_tag_field_class = NULL; - uint64_t i, variant_option_count; - bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); - - BT_COMP_LOGD("Copying content of variant field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - variant_option_count = - bt_field_class_variant_get_option_count(in_field_class); - for (i = 0; i < variant_option_count; i++) { - const bt_field_class *in_option_fc; - const char *option_name; - bt_field_class *out_option_fc; - const bt_field_class_variant_option *in_option; - bt_field_class_variant_option *out_option; - - in_option = bt_field_class_variant_borrow_option_by_index_const( - in_field_class, i); - in_option_fc = bt_field_class_variant_option_borrow_field_class_const( - in_option); - option_name = bt_field_class_variant_option_get_name(in_option); - - out_option_fc = create_field_class_copy_internal( - md_maps, in_option_fc); - if (!out_option_fc) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy variant option field class: " - "in-option-fc=%p, in-option-name=\"%s\"", - in_option_fc, option_name); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; - goto end; - } - - status = copy_field_class_content_internal(md_maps, in_option_fc, - out_option_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error copying content of variant option field class: " - "in-option-fc=%p, in-option-name=\"%s\"", - in_option_fc, option_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_option_fc); - goto end; - } - - if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) { - const bt_field_class_variant_with_selector_field_integer_unsigned_option *spec_opt = - bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const( - in_field_class, i); - const bt_integer_range_set_unsigned *ranges = - bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const( - spec_opt); - enum bt_field_class_variant_with_selector_field_integer_append_option_status append_opt_status = - bt_field_class_variant_with_selector_field_integer_unsigned_append_option( - out_field_class, option_name, - out_option_fc, ranges); - - if (append_opt_status != - BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class with unsigned integer selector" - "out-fc-addr=%p, out-option-fc-addr=%p, " - "out-option-name=\"%s\"", out_field_class, - out_option_fc, option_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); - status = (int) append_opt_status; - goto end; - } - } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) { - const bt_field_class_variant_with_selector_field_integer_signed_option *spec_opt = - bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const( - in_field_class, i); - const bt_integer_range_set_signed *ranges = - bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const( - spec_opt); - - enum bt_field_class_variant_with_selector_field_integer_append_option_status append_opt_status = - bt_field_class_variant_with_selector_field_integer_signed_append_option( - out_field_class, option_name, - out_option_fc, ranges); - if (append_opt_status != - BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class with signed integer selector" - "out-fc-addr=%p, out-option-fc-addr=%p, " - "out-option-name=\"%s\"", out_field_class, - out_option_fc, option_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); - status = (int) append_opt_status; - goto end; - } - } else { - BT_ASSERT(fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD); - - enum bt_field_class_variant_without_selector_append_option_status append_opt_status = - bt_field_class_variant_without_selector_append_option( - out_field_class, option_name, - out_option_fc); - if (append_opt_status != - BT_FIELD_CLASS_VARIANT_WITHOUT_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class" - "out-fc-addr=%p, out-option-fc-addr=%p, " - "out-option-name=\"%s\"", out_field_class, - out_option_fc, option_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); - status = (int) append_opt_status; - goto end; - } - } - - out_option = bt_field_class_variant_borrow_option_by_index( - out_field_class, i); - BT_ASSERT(out_option); - - /* - * Safe to use the same value object because it's frozen - * at this point. - */ - bt_field_class_variant_option_set_user_attributes( - out_option, - bt_field_class_variant_option_borrow_user_attributes_const( - in_option)); - } - - BT_COMP_LOGD("Copied content of variant field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -end: - return status; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_static_array_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of static array field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - /* - * There is no content to copy. Keep this function call anyway for - * logging purposes. - */ - BT_COMP_LOGD("Copied content of static array field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_dynamic_array_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of dynamic array field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - /* - * There is no content to copy. Keep this function call anyway for - * logging purposes. - */ - BT_COMP_LOGD("Copied content of dynamic array field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_option_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of option field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - if (bt_field_class_get_type(out_field_class) == - BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) { - bt_field_class_option_with_selector_field_bool_set_selector_is_reversed( - out_field_class, - bt_field_class_option_with_selector_field_bool_selector_is_reversed( - in_field_class)); - } - - BT_COMP_LOGD("Copied content of option field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static inline -enum debug_info_trace_ir_mapping_status field_class_string_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_COMP_LOGD("Copying content of string field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - /* - * There is no content to copy. Keep this function call anyway for - * logging purposes. - */ - BT_COMP_LOGD("Copied content of string field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - - return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; -} - -static -bt_field_class *copy_field_class_array_element( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_elem_fc) -{ - bt_self_component *self_comp = md_maps->self_comp; - bt_field_class *out_elem_fc = - create_field_class_copy_internal(md_maps, in_elem_fc); - if (!out_elem_fc) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output elem field class from input elem field class for static array: " - "in-fc-addr=%p", in_elem_fc); - goto end; - } - - if (copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc) != - DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output elem field class from input elem field class for static array: " - "in-fc-addr=%p", in_elem_fc); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_elem_fc); - goto end; - } - -end: - return out_elem_fc; -} - -bt_field_class *create_field_class_copy_internal( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class) -{ - bt_self_component *self_comp = md_maps->self_comp; - enum debug_info_trace_ir_mapping_status status; - bt_field_class *out_field_class = NULL; - bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); - - BT_COMP_LOGD("Creating bare field class based on field class: in-fc-addr=%p", - in_field_class); - - switch (fc_type) { - case BT_FIELD_CLASS_TYPE_BOOL: - out_field_class = bt_field_class_bool_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_BIT_ARRAY: - out_field_class = bt_field_class_bit_array_create( - md_maps->output_trace_class, - bt_field_class_bit_array_get_length( - in_field_class)); - break; - case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: - out_field_class = bt_field_class_integer_unsigned_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: - out_field_class = bt_field_class_integer_signed_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: - out_field_class = bt_field_class_enumeration_unsigned_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: - out_field_class = bt_field_class_enumeration_signed_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL: - out_field_class = bt_field_class_real_single_precision_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL: - out_field_class = bt_field_class_real_double_precision_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_STRING: - out_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_STRUCTURE: - out_field_class = bt_field_class_structure_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: - { - const bt_field_class *in_elem_fc = - bt_field_class_array_borrow_element_field_class_const( - in_field_class); - uint64_t array_len = bt_field_class_array_static_get_length( - in_field_class); - - bt_field_class *out_elem_fc = copy_field_class_array_element( - md_maps, in_elem_fc); - if (!out_elem_fc) { - out_field_class = NULL; - goto error; - } - - out_field_class = bt_field_class_array_static_create( - md_maps->output_trace_class, - out_elem_fc, array_len); - break; - } - default: - break; - } - - if (bt_field_class_type_is(fc_type, - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { - const bt_field_class *in_elem_fc = - bt_field_class_array_borrow_element_field_class_const( - in_field_class); - bt_field_class *out_length_fc = NULL; - bt_field_class *out_elem_fc = copy_field_class_array_element( - md_maps, in_elem_fc); - - if (!out_elem_fc) { - out_field_class = NULL; - goto error; - } - - if (fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) { - const bt_field_path *length_fp = - bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const( - in_field_class); - const bt_field_class *in_length_fc = - resolve_field_path_to_field_class(length_fp, - md_maps); - - BT_ASSERT(in_length_fc); - out_length_fc = g_hash_table_lookup(md_maps->field_class_map, - in_length_fc); - BT_ASSERT(out_length_fc); - } - - out_field_class = bt_field_class_array_dynamic_create( - md_maps->output_trace_class, out_elem_fc, out_length_fc); - } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_OPTION)) { - const bt_field_class *in_content_fc = - bt_field_class_option_borrow_field_class_const( - in_field_class); - bt_field_class *out_selector_fc = NULL; - bt_field_class *out_content_fc; - - out_content_fc = create_field_class_copy_internal( - md_maps, in_content_fc); - if (!out_content_fc) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot copy option's content field class: " - "in-content-fc-addr=%p", in_content_fc); - goto error; - } - - status = copy_field_class_content_internal(md_maps, - in_content_fc, out_content_fc); - if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error copying content of option's content field class: " - "in-content-fc-addr=%p, out-content-fc-addr=%p", - in_content_fc, out_content_fc); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_content_fc); - goto error; - } - - if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD) { - out_field_class = - bt_field_class_option_without_selector_create( - md_maps->output_trace_class, - out_content_fc); - } else { - const bt_field_path *in_selector_fp = - bt_field_class_option_with_selector_field_borrow_selector_field_path_const( - in_field_class); - const bt_field_class *in_selector_fc; - - BT_ASSERT(in_selector_fp); - in_selector_fc = resolve_field_path_to_field_class( - in_selector_fp, md_maps); - BT_ASSERT(in_selector_fc); - out_selector_fc = g_hash_table_lookup( - md_maps->field_class_map, in_selector_fc); - BT_ASSERT(out_selector_fc); - - if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) { - out_field_class = - bt_field_class_option_with_selector_field_bool_create( - md_maps->output_trace_class, - out_content_fc, out_selector_fc); - } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) { - const bt_integer_range_set_unsigned *ranges = - bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const( - in_field_class); - - BT_ASSERT(ranges); - out_field_class = - bt_field_class_option_with_selector_field_integer_unsigned_create( - md_maps->output_trace_class, - out_content_fc, out_selector_fc, - ranges); - } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD) { - const bt_integer_range_set_signed *ranges = - bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const( - in_field_class); - - BT_ASSERT(ranges); - out_field_class = - bt_field_class_option_with_selector_field_integer_signed_create( - md_maps->output_trace_class, - out_content_fc, out_selector_fc, - ranges); - } - } - } else if (bt_field_class_type_is(fc_type, - BT_FIELD_CLASS_TYPE_VARIANT)) { - bt_field_class *out_sel_fc = NULL; - - if (bt_field_class_type_is(fc_type, - BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) { - const bt_field_class *in_sel_fc; - const bt_field_path *sel_fp = - bt_field_class_variant_with_selector_field_borrow_selector_field_path_const( - in_field_class); - - BT_ASSERT(sel_fp); - in_sel_fc = resolve_field_path_to_field_class(sel_fp, - md_maps); - BT_ASSERT(in_sel_fc); - out_sel_fc = g_hash_table_lookup( - md_maps->field_class_map, in_sel_fc); - BT_ASSERT(out_sel_fc); - } - - out_field_class = bt_field_class_variant_create( - md_maps->output_trace_class, out_sel_fc); - } - - /* - * Add mapping from in_field_class to out_field_class. This simplifies - * the resolution of field paths in variant and dynamic array field - * classes. - */ - BT_ASSERT(out_field_class); - g_hash_table_insert(md_maps->field_class_map, - (gpointer) in_field_class, out_field_class); - -error: - if(out_field_class){ - BT_COMP_LOGD("Created bare field class based on field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - } else { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Error creating output field class from input field class: " - "in-fc-addr=%p", in_field_class); - } - - return out_field_class; -} - -enum debug_info_trace_ir_mapping_status copy_field_class_content_internal( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - enum debug_info_trace_ir_mapping_status status; - bt_field_class_type in_fc_type = - bt_field_class_get_type(in_field_class); - - /* - * Safe to use the same value object because it's frozen at this - * point. - */ - bt_field_class_set_user_attributes(out_field_class, - bt_field_class_borrow_user_attributes_const(in_field_class)); - - if (in_fc_type == BT_FIELD_CLASS_TYPE_BOOL) { - status = field_class_bool_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) { - status = field_class_bit_array_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) { - status = field_class_unsigned_integer_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) { - status = field_class_signed_integer_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) { - status = field_class_unsigned_enumeration_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) { - status = field_class_signed_enumeration_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { - status = field_class_single_precision_real_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) { - status = field_class_double_precision_real_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRING) { - status = field_class_string_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { - status = field_class_structure_copy(md_maps, - in_field_class, out_field_class); - } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) { - status = field_class_static_array_copy(md_maps, - in_field_class, out_field_class); - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { - status = field_class_dynamic_array_copy(md_maps, - in_field_class, out_field_class); - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_OPTION)) { - status = field_class_option_copy(md_maps, - in_field_class, out_field_class); - } else if (bt_field_class_type_is(in_fc_type, - BT_FIELD_CLASS_TYPE_VARIANT)) { - status = field_class_variant_copy(md_maps, - in_field_class, out_field_class); - } else { - bt_common_abort(); - } - - return status; -} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.cpp b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.cpp new file mode 100644 index 00000000..05a58eb1 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.cpp @@ -0,0 +1,953 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR field copy + */ + +/* clang-format off */ + +#define BT_COMP_LOG_SELF_COMP (md_maps->self_comp) +#define BT_LOG_OUTPUT_LEVEL (md_maps->log_level) +#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/TRACE-IR-META-FC-COPY" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include "common/common.h" +#include "compat/compiler.h" +#include + +#include "trace-ir-metadata-copy.hpp" +#include "trace-ir-metadata-field-class-copy.hpp" + +/* + * This function walks through the nested structures field class to resolve a + * field path object. A field path is made of indexes inside possibly nested + * structures ultimately leading to a field class. + */ +static +const bt_field_class *walk_field_path(struct trace_ir_metadata_maps *md_maps, + const bt_field_path *fp, const bt_field_class *fc) +{ + uint64_t i, fp_item_count; + const bt_field_class *curr_fc; + + BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE); + BT_COMP_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p", + fp, fc); + + fp_item_count = bt_field_path_get_item_count(fp); + curr_fc = fc; + for (i = 0; i < fp_item_count; i++) { + bt_field_class_type fc_type = bt_field_class_get_type(curr_fc); + const bt_field_path_item *fp_item = + bt_field_path_borrow_item_by_index_const(fp, i); + + if (fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { + const bt_field_class_structure_member *member; + + BT_ASSERT(bt_field_path_item_get_type(fp_item) == + BT_FIELD_PATH_ITEM_TYPE_INDEX); + member = bt_field_class_structure_borrow_member_by_index_const( + curr_fc, + bt_field_path_item_index_get_index(fp_item)); + curr_fc = bt_field_class_structure_member_borrow_field_class_const( + member); + } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_OPTION)) { + BT_ASSERT(bt_field_path_item_get_type(fp_item) == + BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT); + curr_fc = bt_field_class_option_borrow_field_class_const( + curr_fc); + + } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) { + const bt_field_class_variant_option *option; + + BT_ASSERT(bt_field_path_item_get_type(fp_item) == + BT_FIELD_PATH_ITEM_TYPE_INDEX); + option = bt_field_class_variant_borrow_option_by_index_const( + curr_fc, + bt_field_path_item_index_get_index(fp_item)); + curr_fc = bt_field_class_variant_option_borrow_field_class_const( + option); + break; + } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) { + BT_ASSERT(bt_field_path_item_get_type(fp_item) == + BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT); + curr_fc = bt_field_class_array_borrow_element_field_class_const( + curr_fc); + break; + } else { + bt_common_abort(); + } + } + + return curr_fc; +} + +static +const bt_field_class *resolve_field_path_to_field_class(const bt_field_path *fp, + struct trace_ir_metadata_maps *md_maps) +{ + struct field_class_resolving_context *fc_resolving_ctx; + const bt_field_class *fc; + bt_field_path_scope fp_scope; + + BT_COMP_LOGD("Resolving field path: fp-addr=%p", fp); + + fc_resolving_ctx = md_maps->fc_resolving_ctx; + fp_scope = bt_field_path_get_root_scope(fp); + + switch (fp_scope) { + case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT: + fc = walk_field_path(md_maps, fp, + fc_resolving_ctx->packet_context); + break; + case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT: + fc = walk_field_path(md_maps, fp, + fc_resolving_ctx->event_common_context); + break; + case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT: + fc = walk_field_path(md_maps, fp, + fc_resolving_ctx->event_specific_context); + break; + case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD: + fc = walk_field_path(md_maps, fp, + fc_resolving_ctx->event_payload); + break; + default: + bt_common_abort(); + } + + return fc; +} + +static inline +void field_class_integer_set_props(const bt_field_class *input_fc, + bt_field_class *output_fc) +{ + bt_field_class_integer_set_preferred_display_base(output_fc, + bt_field_class_integer_get_preferred_display_base(input_fc)); + bt_field_class_integer_set_field_value_range(output_fc, + bt_field_class_integer_get_field_value_range(input_fc)); +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_bool_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of boolean field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + /* + * There is no content to copy. Keep this function call anyway for + * logging purposes. + */ + BT_COMP_LOGD("Copied content of boolean field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_bit_array_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of bit array field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + /* + * There is no content to copy. Keep this function call anyway for + * logging purposes. + */ + BT_COMP_LOGD("Copied content of bit array field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_unsigned_integer_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of unsigned integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + field_class_integer_set_props(in_field_class, out_field_class); + + BT_COMP_LOGD("Copied content of unsigned integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_signed_integer_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of signed integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + field_class_integer_set_props(in_field_class, out_field_class); + + BT_COMP_LOGD("Copied content of signed integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static +enum debug_info_trace_ir_mapping_status field_class_unsigned_enumeration_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + enum debug_info_trace_ir_mapping_status status; + uint64_t i, enum_mapping_count; + + BT_COMP_LOGD("Copying content of unsigned enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + /* Copy properties of the inner integer. */ + field_class_integer_set_props(in_field_class, out_field_class); + + /* Copy all enumeration entries. */ + enum_mapping_count = bt_field_class_enumeration_get_mapping_count( + in_field_class); + for (i = 0; i < enum_mapping_count; i++) { + const char *label; + const bt_integer_range_set_unsigned *range_set; + const bt_field_class_enumeration_unsigned_mapping *u_mapping; + const bt_field_class_enumeration_mapping *mapping; + enum bt_field_class_enumeration_add_mapping_status add_mapping_status; + + u_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const( + in_field_class, i); + mapping = bt_field_class_enumeration_unsigned_mapping_as_mapping_const( + u_mapping); + label = bt_field_class_enumeration_mapping_get_label(mapping); + range_set = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const( + u_mapping); + add_mapping_status = bt_field_class_enumeration_unsigned_add_mapping( + out_field_class, label, range_set); + if (add_mapping_status != BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_OK) { + status = static_cast(add_mapping_status); + goto end; + } + } + + BT_COMP_LOGD("Copied content of unsigned enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_signed_enumeration_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + enum debug_info_trace_ir_mapping_status status; + uint64_t i, enum_mapping_count; + + BT_COMP_LOGD("Copying content of signed enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + /* Copy properties of the inner integer. */ + field_class_integer_set_props(in_field_class, out_field_class); + + /* Copy all enumeration entries. */ + enum_mapping_count = + bt_field_class_enumeration_get_mapping_count(in_field_class); + for (i = 0; i < enum_mapping_count; i++) { + const char *label; + const bt_integer_range_set_signed *range_set; + const bt_field_class_enumeration_signed_mapping *s_mapping; + const bt_field_class_enumeration_mapping *mapping; + enum bt_field_class_enumeration_add_mapping_status add_mapping_status; + + s_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const( + in_field_class, i); + mapping = bt_field_class_enumeration_signed_mapping_as_mapping_const( + s_mapping); + label = bt_field_class_enumeration_mapping_get_label(mapping); + range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const( + s_mapping); + add_mapping_status = bt_field_class_enumeration_signed_add_mapping( + out_field_class, label, range_set); + if (add_mapping_status != BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_OK) { + status = static_cast(add_mapping_status); + goto end; + } + } + + BT_COMP_LOGD("Copied content of signed enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_single_precision_real_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of single-precision real field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + BT_COMP_LOGD("Copied content single-precision real field class:" + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_double_precision_real_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of double-precision real field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + BT_COMP_LOGD("Copied content double-precision real field class:" + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_structure_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + bt_self_component *self_comp = md_maps->self_comp; + uint64_t i, struct_member_count; + enum debug_info_trace_ir_mapping_status status; + + BT_COMP_LOGD("Copying content of structure field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + /* Get the number of member in that struct. */ + struct_member_count = + bt_field_class_structure_get_member_count(in_field_class); + + /* Iterate over all the members of the struct. */ + for (i = 0; i < struct_member_count; i++) { + enum bt_field_class_structure_append_member_status append_member_status; + const bt_field_class_structure_member *in_member; + bt_field_class_structure_member *out_member; + const char *member_name; + const bt_field_class *in_member_fc; + bt_field_class *out_member_fc; + + in_member = bt_field_class_structure_borrow_member_by_index_const( + in_field_class, i); + in_member_fc = bt_field_class_structure_member_borrow_field_class_const( + in_member); + member_name = bt_field_class_structure_member_get_name(in_member); + BT_COMP_LOGD("Copying structure field class's member: " + "index=%" PRId64 ", member-fc-addr=%p, member-name=\"%s\"", + i, in_member_fc, member_name); + + out_member_fc = create_field_class_copy(md_maps, in_member_fc); + if (!out_member_fc) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy structure field class's member: " + "index=%" PRId64 ", in-member-fc-addr=%p, " + "member-name=\"%s\"", i, in_member_fc, + member_name); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto end; + } + + status = copy_field_class_content(md_maps, in_member_fc, + out_member_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy content of structure field class's member: " + "index=%" PRId64 ", in-member-fc-addr=%p, " + "member-name=\"%s\"", i, in_member_fc, + member_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_fc); + goto end; + } + + append_member_status = bt_field_class_structure_append_member(out_field_class, + member_name, out_member_fc); + if (append_member_status != + BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append structure field class's field: " + "index=%" PRId64 ", field-fc-addr=%p, " + "field-name=\"%s\"", i, in_member_fc, + member_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_fc); + status = static_cast(append_member_status); + goto end; + } + + out_member = bt_field_class_structure_borrow_member_by_index( + out_field_class, i); + BT_ASSERT(out_member); + + /* + * Safe to use the same value object because it's frozen + * at this point. + */ + bt_field_class_structure_member_set_user_attributes( + out_member, + bt_field_class_structure_member_borrow_user_attributes_const( + in_member)); + } + + BT_COMP_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p", + in_field_class, out_field_class); + + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_variant_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + bt_self_component *self_comp = md_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + bt_field_class *out_tag_field_class = NULL; + uint64_t i, variant_option_count; + bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); + + BT_COMP_LOGD("Copying content of variant field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + variant_option_count = + bt_field_class_variant_get_option_count(in_field_class); + for (i = 0; i < variant_option_count; i++) { + const bt_field_class *in_option_fc; + const char *option_name; + bt_field_class *out_option_fc; + const bt_field_class_variant_option *in_option; + bt_field_class_variant_option *out_option; + + in_option = bt_field_class_variant_borrow_option_by_index_const( + in_field_class, i); + in_option_fc = bt_field_class_variant_option_borrow_field_class_const( + in_option); + option_name = bt_field_class_variant_option_get_name(in_option); + + out_option_fc = create_field_class_copy_internal( + md_maps, in_option_fc); + if (!out_option_fc) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot copy variant option field class: " + "in-option-fc=%p, in-option-name=\"%s\"", + in_option_fc, option_name); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_MEMORY_ERROR; + goto end; + } + + status = copy_field_class_content_internal(md_maps, in_option_fc, + out_option_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error copying content of variant option field class: " + "in-option-fc=%p, in-option-name=\"%s\"", + in_option_fc, option_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_option_fc); + goto end; + } + + if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) { + const bt_field_class_variant_with_selector_field_integer_unsigned_option *spec_opt = + bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const( + in_field_class, i); + const bt_integer_range_set_unsigned *ranges = + bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const( + spec_opt); + enum bt_field_class_variant_with_selector_field_integer_append_option_status append_opt_status = + bt_field_class_variant_with_selector_field_integer_unsigned_append_option( + out_field_class, option_name, + out_option_fc, ranges); + + if (append_opt_status != + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class with unsigned integer selector" + "out-fc-addr=%p, out-option-fc-addr=%p, " + "out-option-name=\"%s\"", out_field_class, + out_option_fc, option_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + status = static_cast(append_opt_status); + goto end; + } + } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD) { + const bt_field_class_variant_with_selector_field_integer_signed_option *spec_opt = + bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const( + in_field_class, i); + const bt_integer_range_set_signed *ranges = + bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const( + spec_opt); + + enum bt_field_class_variant_with_selector_field_integer_append_option_status append_opt_status = + bt_field_class_variant_with_selector_field_integer_signed_append_option( + out_field_class, option_name, + out_option_fc, ranges); + if (append_opt_status != + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class with signed integer selector" + "out-fc-addr=%p, out-option-fc-addr=%p, " + "out-option-name=\"%s\"", out_field_class, + out_option_fc, option_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + status = static_cast(append_opt_status); + goto end; + } + } else { + BT_ASSERT(fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD); + + enum bt_field_class_variant_without_selector_append_option_status append_opt_status = + bt_field_class_variant_without_selector_append_option( + out_field_class, option_name, + out_option_fc); + if (append_opt_status != + BT_FIELD_CLASS_VARIANT_WITHOUT_SELECTOR_FIELD_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot append option to variant field class" + "out-fc-addr=%p, out-option-fc-addr=%p, " + "out-option-name=\"%s\"", out_field_class, + out_option_fc, option_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + status = static_cast(append_opt_status); + goto end; + } + } + + out_option = bt_field_class_variant_borrow_option_by_index( + out_field_class, i); + BT_ASSERT(out_option); + + /* + * Safe to use the same value object because it's frozen + * at this point. + */ + bt_field_class_variant_option_set_user_attributes( + out_option, + bt_field_class_variant_option_borrow_user_attributes_const( + in_option)); + } + + BT_COMP_LOGD("Copied content of variant field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + status = DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +end: + return status; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_static_array_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of static array field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + /* + * There is no content to copy. Keep this function call anyway for + * logging purposes. + */ + BT_COMP_LOGD("Copied content of static array field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_dynamic_array_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of dynamic array field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + /* + * There is no content to copy. Keep this function call anyway for + * logging purposes. + */ + BT_COMP_LOGD("Copied content of dynamic array field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_option_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of option field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + if (bt_field_class_get_type(out_field_class) == + BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) { + bt_field_class_option_with_selector_field_bool_set_selector_is_reversed( + out_field_class, + bt_field_class_option_with_selector_field_bool_selector_is_reversed( + in_field_class)); + } + + BT_COMP_LOGD("Copied content of option field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static inline +enum debug_info_trace_ir_mapping_status field_class_string_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_COMP_LOGD("Copying content of string field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + /* + * There is no content to copy. Keep this function call anyway for + * logging purposes. + */ + BT_COMP_LOGD("Copied content of string field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + + return DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK; +} + +static +bt_field_class *copy_field_class_array_element( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_elem_fc) +{ + bt_self_component *self_comp = md_maps->self_comp; + bt_field_class *out_elem_fc = + create_field_class_copy_internal(md_maps, in_elem_fc); + if (!out_elem_fc) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output elem field class from input elem field class for static array: " + "in-fc-addr=%p", in_elem_fc); + goto end; + } + + if (copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc) != + DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output elem field class from input elem field class for static array: " + "in-fc-addr=%p", in_elem_fc); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_elem_fc); + goto end; + } + +end: + return out_elem_fc; +} + +bt_field_class *create_field_class_copy_internal( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class) +{ + bt_self_component *self_comp = md_maps->self_comp; + enum debug_info_trace_ir_mapping_status status; + bt_field_class *out_field_class = NULL; + bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); + + BT_COMP_LOGD("Creating bare field class based on field class: in-fc-addr=%p", + in_field_class); + + switch (fc_type) { + case BT_FIELD_CLASS_TYPE_BOOL: + out_field_class = bt_field_class_bool_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_BIT_ARRAY: + out_field_class = bt_field_class_bit_array_create( + md_maps->output_trace_class, + bt_field_class_bit_array_get_length( + in_field_class)); + break; + case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: + out_field_class = bt_field_class_integer_unsigned_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: + out_field_class = bt_field_class_integer_signed_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: + out_field_class = bt_field_class_enumeration_unsigned_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: + out_field_class = bt_field_class_enumeration_signed_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL: + out_field_class = bt_field_class_real_single_precision_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL: + out_field_class = bt_field_class_real_double_precision_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_STRING: + out_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_STRUCTURE: + out_field_class = bt_field_class_structure_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: + { + const bt_field_class *in_elem_fc = + bt_field_class_array_borrow_element_field_class_const( + in_field_class); + uint64_t array_len = bt_field_class_array_static_get_length( + in_field_class); + + bt_field_class *out_elem_fc = copy_field_class_array_element( + md_maps, in_elem_fc); + if (!out_elem_fc) { + out_field_class = NULL; + goto error; + } + + out_field_class = bt_field_class_array_static_create( + md_maps->output_trace_class, + out_elem_fc, array_len); + break; + } + default: + break; + } + + if (bt_field_class_type_is(fc_type, + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { + const bt_field_class *in_elem_fc = + bt_field_class_array_borrow_element_field_class_const( + in_field_class); + bt_field_class *out_length_fc = NULL; + bt_field_class *out_elem_fc = copy_field_class_array_element( + md_maps, in_elem_fc); + + if (!out_elem_fc) { + out_field_class = NULL; + goto error; + } + + if (fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) { + const bt_field_path *length_fp = + bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const( + in_field_class); + const bt_field_class *in_length_fc = + resolve_field_path_to_field_class(length_fp, + md_maps); + + BT_ASSERT(in_length_fc); + out_length_fc = static_cast(g_hash_table_lookup(md_maps->field_class_map, + in_length_fc)); + BT_ASSERT(out_length_fc); + } + + out_field_class = bt_field_class_array_dynamic_create( + md_maps->output_trace_class, out_elem_fc, out_length_fc); + } else if (bt_field_class_type_is(fc_type, BT_FIELD_CLASS_TYPE_OPTION)) { + const bt_field_class *in_content_fc = + bt_field_class_option_borrow_field_class_const( + in_field_class); + bt_field_class *out_selector_fc = NULL; + bt_field_class *out_content_fc; + + out_content_fc = create_field_class_copy_internal( + md_maps, in_content_fc); + if (!out_content_fc) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot copy option's content field class: " + "in-content-fc-addr=%p", in_content_fc); + goto error; + } + + status = copy_field_class_content_internal(md_maps, + in_content_fc, out_content_fc); + if (status != DEBUG_INFO_TRACE_IR_MAPPING_STATUS_OK) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error copying content of option's content field class: " + "in-content-fc-addr=%p, out-content-fc-addr=%p", + in_content_fc, out_content_fc); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_content_fc); + goto error; + } + + if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD) { + out_field_class = + bt_field_class_option_without_selector_create( + md_maps->output_trace_class, + out_content_fc); + } else { + const bt_field_path *in_selector_fp = + bt_field_class_option_with_selector_field_borrow_selector_field_path_const( + in_field_class); + const bt_field_class *in_selector_fc; + + BT_ASSERT(in_selector_fp); + in_selector_fc = resolve_field_path_to_field_class( + in_selector_fp, md_maps); + BT_ASSERT(in_selector_fc); + out_selector_fc = static_cast(g_hash_table_lookup( + md_maps->field_class_map, in_selector_fc)); + BT_ASSERT(out_selector_fc); + + if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD) { + out_field_class = + bt_field_class_option_with_selector_field_bool_create( + md_maps->output_trace_class, + out_content_fc, out_selector_fc); + } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) { + const bt_integer_range_set_unsigned *ranges = + bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const( + in_field_class); + + BT_ASSERT(ranges); + out_field_class = + bt_field_class_option_with_selector_field_integer_unsigned_create( + md_maps->output_trace_class, + out_content_fc, out_selector_fc, + ranges); + } else if (fc_type == BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD) { + const bt_integer_range_set_signed *ranges = + bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const( + in_field_class); + + BT_ASSERT(ranges); + out_field_class = + bt_field_class_option_with_selector_field_integer_signed_create( + md_maps->output_trace_class, + out_content_fc, out_selector_fc, + ranges); + } + } + } else if (bt_field_class_type_is(fc_type, + BT_FIELD_CLASS_TYPE_VARIANT)) { + bt_field_class *out_sel_fc = NULL; + + if (bt_field_class_type_is(fc_type, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) { + const bt_field_class *in_sel_fc; + const bt_field_path *sel_fp = + bt_field_class_variant_with_selector_field_borrow_selector_field_path_const( + in_field_class); + + BT_ASSERT(sel_fp); + in_sel_fc = resolve_field_path_to_field_class(sel_fp, + md_maps); + BT_ASSERT(in_sel_fc); + out_sel_fc = static_cast(g_hash_table_lookup( + md_maps->field_class_map, in_sel_fc)); + BT_ASSERT(out_sel_fc); + } + + out_field_class = bt_field_class_variant_create( + md_maps->output_trace_class, out_sel_fc); + } + + /* + * Add mapping from in_field_class to out_field_class. This simplifies + * the resolution of field paths in variant and dynamic array field + * classes. + */ + BT_ASSERT(out_field_class); + g_hash_table_insert(md_maps->field_class_map, + (gpointer) in_field_class, out_field_class); + +error: + if(out_field_class){ + BT_COMP_LOGD("Created bare field class based on field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + } else { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Error creating output field class from input field class: " + "in-fc-addr=%p", in_field_class); + } + + return out_field_class; +} + +enum debug_info_trace_ir_mapping_status copy_field_class_content_internal( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + enum debug_info_trace_ir_mapping_status status; + bt_field_class_type in_fc_type = + bt_field_class_get_type(in_field_class); + + /* + * Safe to use the same value object because it's frozen at this + * point. + */ + bt_field_class_set_user_attributes(out_field_class, + bt_field_class_borrow_user_attributes_const(in_field_class)); + + if (in_fc_type == BT_FIELD_CLASS_TYPE_BOOL) { + status = field_class_bool_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) { + status = field_class_bit_array_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) { + status = field_class_unsigned_integer_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) { + status = field_class_signed_integer_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) { + status = field_class_unsigned_enumeration_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) { + status = field_class_signed_enumeration_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { + status = field_class_single_precision_real_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL) { + status = field_class_double_precision_real_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRING) { + status = field_class_string_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { + status = field_class_structure_copy(md_maps, + in_field_class, out_field_class); + } else if (in_fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) { + status = field_class_static_array_copy(md_maps, + in_field_class, out_field_class); + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) { + status = field_class_dynamic_array_copy(md_maps, + in_field_class, out_field_class); + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_OPTION)) { + status = field_class_option_copy(md_maps, + in_field_class, out_field_class); + } else if (bt_field_class_type_is(in_fc_type, + BT_FIELD_CLASS_TYPE_VARIANT)) { + status = field_class_variant_copy(md_maps, + in_field_class, out_field_class); + } else { + bt_common_abort(); + } + + return status; +} diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h deleted file mode 100644 index 84802c9d..00000000 --- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Babeltrace - Trace IR metadata field class copy - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_H - -#include -#include "common/macros.h" -#include "trace-ir-mapping.h" - -enum debug_info_trace_ir_mapping_status copy_field_class_content_internal( - struct trace_ir_metadata_maps *trace_ir_metadata_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class); - -bt_field_class *create_field_class_copy_internal( - struct trace_ir_metadata_maps *trace_ir_metadata_maps, - const bt_field_class *in_field_class); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_H */ diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.hpp b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.hpp new file mode 100644 index 00000000..a5272543 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.hpp @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Babeltrace - Trace IR metadata field class copy + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_HPP + +#include +#include "common/macros.h" +#include "trace-ir-mapping.hpp" + +enum debug_info_trace_ir_mapping_status copy_field_class_content_internal( + struct trace_ir_metadata_maps *trace_ir_metadata_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class); + +bt_field_class *create_field_class_copy_internal( + struct trace_ir_metadata_maps *trace_ir_metadata_maps, + const bt_field_class *in_field_class); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_TRACE_IR_METADATA_FIELD_CLASS_COPY_HPP */ diff --git a/src/plugins/lttng-utils/debug-info/utils.c b/src/plugins/lttng-utils/debug-info/utils.c deleted file mode 100644 index 3c160bc4..00000000 --- a/src/plugins/lttng-utils/debug-info/utils.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2016 Jérémie Galarneau - * - * Babeltrace - Debug info utilities - */ - -#include -#include - -#include - -#include "debug-info.h" -#include "utils.h" - -const char *get_filename_from_path(const char *path) -{ - size_t i = strlen(path); - - if (i == 0) { - goto end; - } - - if (path[i - 1] == '/') { - /* - * Path ends with a trailing slash, no filename to return. - * Return the original path. - */ - goto end; - } - - while (i-- > 0) { - if (path[i] == '/') { - path = &path[i + 1]; - goto end; - } - } -end: - return path; -} - -bool is_event_common_ctx_dbg_info_compatible(const bt_field_class *in_field_class, - const char *debug_info_field_class_name) -{ - const bt_field_class_structure_member *member; - const bt_field_class *ip_fc, *vpid_fc; - bool match = false; - - /* - * If the debug info field is already present in the event common - * context. Do not try to add it. - */ - member = bt_field_class_structure_borrow_member_by_name_const( - in_field_class, debug_info_field_class_name); - if (member) { - goto end; - } - - /* - * Verify that the ip and vpid field are present and of the right field - * class. - */ - member = bt_field_class_structure_borrow_member_by_name_const( - in_field_class, IP_FIELD_NAME); - if (!member) { - goto end; - } - - ip_fc = bt_field_class_structure_member_borrow_field_class_const( - member); - if (bt_field_class_get_type(ip_fc) != - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) { - goto end; - } - - member = bt_field_class_structure_borrow_member_by_name_const( - in_field_class, VPID_FIELD_NAME); - if (!member) { - goto end; - } - - vpid_fc = bt_field_class_structure_member_borrow_field_class_const( - member); - if (bt_field_class_get_type(vpid_fc) != - BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) { - goto end; - } - - if (bt_field_class_integer_get_field_value_range(vpid_fc) != 32) { - goto end; - } - - match = true; - -end: - return match; -} diff --git a/src/plugins/lttng-utils/debug-info/utils.cpp b/src/plugins/lttng-utils/debug-info/utils.cpp new file mode 100644 index 00000000..ae009047 --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/utils.cpp @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2016 Jérémie Galarneau + * + * Babeltrace - Debug info utilities + */ + +/* clang-format off */ + +#include +#include + +#include + +#include "debug-info.hpp" +#include "utils.hpp" + +const char *get_filename_from_path(const char *path) +{ + size_t i = strlen(path); + + if (i == 0) { + goto end; + } + + if (path[i - 1] == '/') { + /* + * Path ends with a trailing slash, no filename to return. + * Return the original path. + */ + goto end; + } + + while (i-- > 0) { + if (path[i] == '/') { + path = &path[i + 1]; + goto end; + } + } +end: + return path; +} + +bool is_event_common_ctx_dbg_info_compatible(const bt_field_class *in_field_class, + const char *debug_info_field_class_name) +{ + const bt_field_class_structure_member *member; + const bt_field_class *ip_fc, *vpid_fc; + bool match = false; + + /* + * If the debug info field is already present in the event common + * context. Do not try to add it. + */ + member = bt_field_class_structure_borrow_member_by_name_const( + in_field_class, debug_info_field_class_name); + if (member) { + goto end; + } + + /* + * Verify that the ip and vpid field are present and of the right field + * class. + */ + member = bt_field_class_structure_borrow_member_by_name_const( + in_field_class, IP_FIELD_NAME); + if (!member) { + goto end; + } + + ip_fc = bt_field_class_structure_member_borrow_field_class_const( + member); + if (bt_field_class_get_type(ip_fc) != + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) { + goto end; + } + + member = bt_field_class_structure_borrow_member_by_name_const( + in_field_class, VPID_FIELD_NAME); + if (!member) { + goto end; + } + + vpid_fc = bt_field_class_structure_member_borrow_field_class_const( + member); + if (bt_field_class_get_type(vpid_fc) != + BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) { + goto end; + } + + if (bt_field_class_integer_get_field_value_range(vpid_fc) != 32) { + goto end; + } + + match = true; + +end: + return match; +} diff --git a/src/plugins/lttng-utils/debug-info/utils.h b/src/plugins/lttng-utils/debug-info/utils.h deleted file mode 100644 index 4d9310d9..00000000 --- a/src/plugins/lttng-utils/debug-info/utils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016 Jérémie Galarneau - * - * Babeltrace - Debug Info Utilities - */ - -#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_H -#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_H - -#include - -#include - -#include "common/macros.h" - -/* - * Return the location of a path's file (the last element of the path). - * Returns the original path on error. - */ -const char *get_filename_from_path(const char *path); - -bool is_event_common_ctx_dbg_info_compatible( - const bt_field_class *in_field_class, - const char *debug_info_field_class_name); - -#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_H */ diff --git a/src/plugins/lttng-utils/debug-info/utils.hpp b/src/plugins/lttng-utils/debug-info/utils.hpp new file mode 100644 index 00000000..c5e4162a --- /dev/null +++ b/src/plugins/lttng-utils/debug-info/utils.hpp @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016 Jérémie Galarneau + * + * Babeltrace - Debug Info Utilities + */ + +/* clang-format off */ + +#ifndef BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_HPP +#define BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_HPP + +#include + +#include + +#include "common/macros.h" + +/* + * Return the location of a path's file (the last element of the path). + * Returns the original path on error. + */ +const char *get_filename_from_path(const char *path); + +bool is_event_common_ctx_dbg_info_compatible( + const bt_field_class *in_field_class, + const char *debug_info_field_class_name); + +#endif /* BABELTRACE_PLUGINS_LTTNG_UTILS_DEBUG_INFO_UTILS_HPP */ diff --git a/src/plugins/lttng-utils/plugin.c b/src/plugins/lttng-utils/plugin.c deleted file mode 100644 index 241c313f..00000000 --- a/src/plugins/lttng-utils/plugin.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016 Jérémie Galarneau - * - * Babeltrace Debug Info Plug-in - */ - -#include -#include "debug-info/debug-info.h" - -#ifndef BT_BUILT_IN_PLUGINS -BT_PLUGIN_MODULE(); -#endif - -/* Initialize plug-in entry points. */ -BT_PLUGIN_WITH_ID(lttng_utils, "lttng-utils"); -BT_PLUGIN_DESCRIPTION_WITH_ID(lttng_utils, "LTTng-specific graph utilities"); -BT_PLUGIN_AUTHOR_WITH_ID(lttng_utils, "EfficiOS "); -BT_PLUGIN_LICENSE_WITH_ID(lttng_utils, "MIT"); - -BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID(lttng_utils, debug_info, "debug-info", - debug_info_msg_iter_next); -BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION_WITH_ID(lttng_utils, debug_info, - "Augment compatible events with debugging information."); -BT_PLUGIN_FILTER_COMPONENT_CLASS_HELP_WITH_ID(lttng_utils, debug_info, - "See the babeltrace2-filter.lttng-utils.debug-info(7) manual page."); -BT_PLUGIN_FILTER_COMPONENT_CLASS_INITIALIZE_METHOD_WITH_ID(lttng_utils, - debug_info, debug_info_comp_init); -BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(lttng_utils, - debug_info, debug_info_comp_finalize); -BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_WITH_ID( - lttng_utils, debug_info, debug_info_msg_iter_init); -BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHODS_WITH_ID( - lttng_utils, debug_info, - debug_info_msg_iter_seek_beginning, - debug_info_msg_iter_can_seek_beginning); -BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD_WITH_ID( - lttng_utils, debug_info, debug_info_msg_iter_finalize); diff --git a/src/plugins/lttng-utils/plugin.cpp b/src/plugins/lttng-utils/plugin.cpp new file mode 100644 index 00000000..42150a59 --- /dev/null +++ b/src/plugins/lttng-utils/plugin.cpp @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016 Jérémie Galarneau + * + * Babeltrace Debug Info Plug-in + */ + +/* clang-format off */ + +#include +#include "debug-info/debug-info.hpp" + +#ifndef BT_BUILT_IN_PLUGINS +BT_PLUGIN_MODULE(); +#endif + +/* Initialize plug-in entry points. */ +BT_PLUGIN_WITH_ID(lttng_utils, "lttng-utils"); +BT_PLUGIN_DESCRIPTION_WITH_ID(lttng_utils, "LTTng-specific graph utilities"); +BT_PLUGIN_AUTHOR_WITH_ID(lttng_utils, "EfficiOS "); +BT_PLUGIN_LICENSE_WITH_ID(lttng_utils, "MIT"); + +BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID(lttng_utils, debug_info, "debug-info", + debug_info_msg_iter_next); +BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION_WITH_ID(lttng_utils, debug_info, + "Augment compatible events with debugging information."); +BT_PLUGIN_FILTER_COMPONENT_CLASS_HELP_WITH_ID(lttng_utils, debug_info, + "See the babeltrace2-filter.lttng-utils.debug-info(7) manual page."); +BT_PLUGIN_FILTER_COMPONENT_CLASS_INITIALIZE_METHOD_WITH_ID(lttng_utils, + debug_info, debug_info_comp_init); +BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(lttng_utils, + debug_info, debug_info_comp_finalize); +BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_WITH_ID( + lttng_utils, debug_info, debug_info_msg_iter_init); +BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHODS_WITH_ID( + lttng_utils, debug_info, + debug_info_msg_iter_seek_beginning, + debug_info_msg_iter_can_seek_beginning); +BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD_WITH_ID( + lttng_utils, debug_info, debug_info_msg_iter_finalize); diff --git a/tests/plugins/flt.lttng-utils.debug-info/Makefile.am b/tests/plugins/flt.lttng-utils.debug-info/Makefile.am index 4a58bfca..4e986205 100644 --- a/tests/plugins/flt.lttng-utils.debug-info/Makefile.am +++ b/tests/plugins/flt.lttng-utils.debug-info/Makefile.am @@ -33,7 +33,7 @@ test_dwarf_LDADD = \ $(top_builddir)/src/common/libcommon.la \ $(ELFUTILS_LIBS) \ $(LIBTAP) -test_dwarf_SOURCES = test-dwarf.c +test_dwarf_SOURCES = test-dwarf.cpp test_bin_info_LDADD = \ $(top_builddir)/src/plugins/lttng-utils/debug-info/libdebug-info.la \ @@ -43,7 +43,7 @@ test_bin_info_LDADD = \ $(top_builddir)/src/lib/libbabeltrace2.la \ $(ELFUTILS_LIBS) \ $(LIBTAP) -test_bin_info_SOURCES = test-bin-info.c +test_bin_info_SOURCES = test-bin-info.cpp nodist_EXTRA_test_bin_info_SOURCES = dummy.cpp endif # ENABLE_DEBUG_INFO diff --git a/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.c b/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.c deleted file mode 100644 index 3e6e7a66..00000000 --- a/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (C) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (C) 2015 Antoine Busque - * Copyright (C) 2019 Michael Jeanson - * - * Babeltrace SO info tests - */ - -#define BT_LOG_OUTPUT_LEVEL ((bt_logging_level) BT_LOG_WARNING) -#define BT_LOG_TAG "TEST/BIN-INFO" -#include "logging/log.h" - -#include -#include -#include -#include -#include - -#include "common/macros.h" -#include "common/assert.h" -#include - -#include "tap/tap.h" - -#define NR_TESTS 57 - -#define SO_NAME "libhello-so" -#define DEBUG_NAME "libhello-so.debug" -#define FUNC_FOO_FILENAME "./libhello.c" -#define FUNC_FOO_PRINTF_NAME_FMT "foo+0x%" PRIx64 -#define FUNC_FOO_NAME_LEN 64 - -#define DWARF_DIR_NAME "dwarf-full" -#define ELF_DIR_NAME "elf-only" -#define BUILDID_DIR_NAME "build-id" -#define DEBUGLINK_DIR_NAME "debug-link" - -/* Lower bound of PIC address mapping */ -#define SO_LOW_ADDR 0x400000 -/* Size of PIC address mapping */ -#define SO_MEMSZ 0x800000 -/* An address outside the PIC mapping */ -#define SO_INV_ADDR 0x200000 - -#define BUILD_ID_HEX_LEN 20 - -static uint64_t opt_func_foo_addr; -static uint64_t opt_func_foo_printf_offset; -static uint64_t opt_func_foo_printf_line_no; -static uint64_t opt_func_foo_tp_offset; -static uint64_t opt_func_foo_tp_line_no; -static uint64_t opt_debug_link_crc; -static gchar *opt_build_id; -static gchar *opt_debug_info_dir; - -static uint64_t func_foo_printf_addr; -static uint64_t func_foo_tp_addr; -static char func_foo_printf_name[FUNC_FOO_NAME_LEN]; -static uint8_t build_id[BUILD_ID_HEX_LEN]; - -static GOptionEntry entries[] = { - {"foo-addr", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_addr, - "Offset to printf in foo", "0xX"}, - {"printf-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_printf_offset, - "Offset to printf in foo", "0xX"}, - {"printf-lineno", 0, 0, G_OPTION_ARG_INT64, - &opt_func_foo_printf_line_no, "Line number to printf in foo", "N"}, - {"tp-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_offset, - "Offset to tp in foo", "0xX"}, - {"tp-lineno", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_line_no, - "Line number to tp in foo", "N"}, - {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64, &opt_debug_link_crc, - "Debug link CRC", "0xX"}, - {"build-id", 0, 0, G_OPTION_ARG_STRING, &opt_build_id, "Build ID", - "XXXXXXXXXXXXXXX"}, - {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir, - "Debug info directory", NULL}, - {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}}; - -static -int build_id_to_bin(void) -{ - int ret, len, i; - - if (!opt_build_id) { - goto error; - } - - len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2); - if (len != (BUILD_ID_HEX_LEN * 2)) { - goto error; - } - - for (i = 0; i < (len / 2); i++) { - ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]); - if (ret != 1) { - goto error; - } - } - - if (i != BUILD_ID_HEX_LEN) { - goto error; - } - - return 0; -error: - return -1; -} - -static -void subtest_has_address(struct bin_info *bin, uint64_t addr) -{ - int ret; - - ret = bin_info_has_address(bin, SO_LOW_ADDR - 1); - ok(ret == 0, "bin_info_has_address - address under SO's range"); - - ret = bin_info_has_address(bin, SO_LOW_ADDR); - ok(ret == 1, "bin_info_has_address - lower bound of SO's range"); - - ret = bin_info_has_address(bin, addr); - ok(ret == 1, "bin_info_has_address - address in SO's range"); - - ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1); - ok(ret == 1, "bin_info_has_address - upper bound of SO's range"); - - ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ); - ok(ret == 0, "bin_info_has_address - address above SO's range"); -} - -static -void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr, - char *func_name) -{ - int ret; - char *_func_name = NULL; - - ret = bin_info_lookup_function_name(bin, addr, &_func_name); - ok(ret == 0, "bin_info_lookup_function_name successful at 0x%" PRIx64, addr); - if (_func_name) { - ok(strcmp(_func_name, func_name) == 0, - "bin_info_lookup_function_name - correct function name (%s == %s)", - func_name, _func_name); - free(_func_name); - _func_name = NULL; - } else { - skip(1, - "bin_info_lookup_function_name - function name is NULL"); - } - - /* Test function name lookup - erroneous address */ - ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name); - ok(ret == -1 && !_func_name, - "bin_info_lookup_function_name - fail on invalid addr"); - free(_func_name); -} - -static -void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr, - uint64_t line_no, const char *filename) -{ - int ret; - struct source_location *src_loc = NULL; - - ret = bin_info_lookup_source_location(bin, addr, &src_loc); - ok(ret == 0, "bin_info_lookup_source_location successful at 0x%" PRIx64, - addr); - if (src_loc) { - ok(src_loc->line_no == line_no, - "bin_info_lookup_source_location - correct line_no (%" PRIu64 " == %" PRIu64 ")", - line_no, src_loc->line_no); - ok(strcmp(src_loc->filename, filename) == 0, - "bin_info_lookup_source_location - correct filename (%s == %s)", - filename, src_loc->filename); - source_location_destroy(src_loc); - src_loc = NULL; - } else { - fail("bin_info_lookup_source_location - src_loc is NULL"); - fail("bin_info_lookup_source_location - src_loc is NULL"); - } - - /* Test source location lookup - erroneous address */ - ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc); - ok(ret == -1 && !src_loc, - "bin_info_lookup_source_location - fail on invalid addr"); - if (src_loc) { - source_location_destroy(src_loc); - } -} - -static -void test_bin_info_build_id(const char *bin_info_dir) -{ - int ret; - char *data_dir, *bin_path; - struct bin_info *bin = NULL; - struct bt_fd_cache fdc; - uint8_t invalid_build_id[BUILD_ID_HEX_LEN] = { - 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd, - 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb - }; - - diag("bin-info tests - separate DWARF via build ID"); - - data_dir = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, NULL); - bin_path = - g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL); - - if (!data_dir || !bin_path) { - exit(EXIT_FAILURE); - } - - ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); - if (ret != 0) { - diag("Failed to initialize FD cache"); - exit(EXIT_FAILURE); - } - - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, - data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); - ok(bin, "bin_info_create successful (%s)", bin_path); - - /* Test setting invalid build_id */ - ret = bin_info_set_build_id(bin, invalid_build_id, BUILD_ID_HEX_LEN); - ok(ret == -1, "bin_info_set_build_id fail on invalid build_id"); - - /* Test setting correct build_id */ - ret = bin_info_set_build_id(bin, build_id, BUILD_ID_HEX_LEN); - ok(ret == 0, "bin_info_set_build_id successful"); - - /* Test bin_info_has_address */ - subtest_has_address(bin, func_foo_printf_addr); - - /* Test function name lookup (with DWARF) */ - subtest_lookup_function_name(bin, func_foo_printf_addr, - func_foo_printf_name); - - /* Test source location lookup */ - subtest_lookup_source_location(bin, func_foo_printf_addr, - opt_func_foo_printf_line_no, - FUNC_FOO_FILENAME); - - bin_info_destroy(bin); - bt_fd_cache_fini(&fdc); - g_free(data_dir); - g_free(bin_path); -} - -static -void test_bin_info_debug_link(const char *bin_info_dir) -{ - int ret; - char *data_dir, *bin_path; - struct bin_info *bin = NULL; - struct bt_fd_cache fdc; - - diag("bin-info tests - separate DWARF via debug link"); - - data_dir = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, NULL); - bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME, - NULL); - - if (!data_dir || !bin_path) { - exit(EXIT_FAILURE); - } - - ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); - if (ret != 0) { - diag("Failed to initialize FD cache"); - exit(EXIT_FAILURE); - } - - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, - data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); - ok(bin, "bin_info_create successful (%s)", bin_path); - - /* Test setting debug link */ - ret = bin_info_set_debug_link(bin, DEBUG_NAME, opt_debug_link_crc); - ok(ret == 0, "bin_info_set_debug_link successful"); - - /* Test bin_info_has_address */ - subtest_has_address(bin, func_foo_printf_addr); - - /* Test function name lookup (with DWARF) */ - subtest_lookup_function_name(bin, func_foo_printf_addr, - func_foo_printf_name); - - /* Test source location lookup */ - subtest_lookup_source_location(bin, func_foo_printf_addr, - opt_func_foo_printf_line_no, - FUNC_FOO_FILENAME); - - bin_info_destroy(bin); - bt_fd_cache_fini(&fdc); - g_free(data_dir); - g_free(bin_path); -} - -static -void test_bin_info_elf(const char *bin_info_dir) -{ - int ret; - char *data_dir, *bin_path; - struct bin_info *bin = NULL; - struct source_location *src_loc = NULL; - struct bt_fd_cache fdc; - - diag("bin-info tests - ELF only"); - - data_dir = g_build_filename(bin_info_dir, ELF_DIR_NAME, NULL); - bin_path = g_build_filename(bin_info_dir, ELF_DIR_NAME, SO_NAME, NULL); - - if (!data_dir || !bin_path) { - exit(EXIT_FAILURE); - } - - ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); - if (ret != 0) { - diag("Failed to initialize FD cache"); - exit(EXIT_FAILURE); - } - - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, - data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); - ok(bin, "bin_info_create successful (%s)", bin_path); - - /* Test bin_info_has_address */ - subtest_has_address(bin, func_foo_printf_addr); - - /* Test function name lookup (with ELF) */ - subtest_lookup_function_name(bin, func_foo_printf_addr, - func_foo_printf_name); - - /* Test source location location - should fail on ELF only file */ - ret = bin_info_lookup_source_location(bin, func_foo_printf_addr, - &src_loc); - ok(ret == -1, - "bin_info_lookup_source_location - fail on ELF only file"); - - source_location_destroy(src_loc); - bin_info_destroy(bin); - bt_fd_cache_fini(&fdc); - g_free(data_dir); - g_free(bin_path); -} - -static -void test_bin_info_bundled(const char *bin_info_dir) -{ - int ret; - char *data_dir, *bin_path; - struct bin_info *bin = NULL; - struct bt_fd_cache fdc; - - diag("bin-info tests - DWARF bundled in SO file"); - - data_dir = g_build_filename(bin_info_dir, DWARF_DIR_NAME, NULL); - bin_path = - g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL); - - if (!data_dir || !bin_path) { - exit(EXIT_FAILURE); - } - - ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); - if (ret != 0) { - diag("Failed to initialize FD cache"); - exit(EXIT_FAILURE); - } - - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, - data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); - ok(bin, "bin_info_create successful (%s)", bin_path); - - /* Test bin_info_has_address */ - subtest_has_address(bin, func_foo_printf_addr); - - /* Test function name lookup (with DWARF) */ - subtest_lookup_function_name(bin, func_foo_printf_addr, - func_foo_printf_name); - - /* Test source location lookup */ - subtest_lookup_source_location(bin, func_foo_printf_addr, - opt_func_foo_printf_line_no, - FUNC_FOO_FILENAME); - - /* Test source location lookup - inlined function */ - subtest_lookup_source_location(bin, func_foo_tp_addr, - opt_func_foo_tp_line_no, - FUNC_FOO_FILENAME); - - bin_info_destroy(bin); - bt_fd_cache_fini(&fdc); - g_free(data_dir); - g_free(bin_path); -} - -int main(int argc, char **argv) -{ - int ret; - GError *error = NULL; - GOptionContext *context; - int status; - - plan_tests(NR_TESTS); - - context = g_option_context_new("- bin info test"); - g_option_context_add_main_entries(context, entries, NULL); - if (!g_option_context_parse(context, &argc, &argv, &error)) { - fprintf(stderr, "option parsing failed: %s\n", error->message); - status = EXIT_FAILURE; - goto end; - } - - g_snprintf(func_foo_printf_name, FUNC_FOO_NAME_LEN, - FUNC_FOO_PRINTF_NAME_FMT, opt_func_foo_printf_offset); - func_foo_printf_addr = - SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_printf_offset; - func_foo_tp_addr = - SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_tp_offset; - - if (build_id_to_bin()) { - fprintf(stderr, "Failed to parse / missing build id\n"); - status = EXIT_FAILURE; - goto end; - } - - ret = bin_info_init(BT_LOG_OUTPUT_LEVEL, NULL); - ok(ret == 0, "bin_info_init successful"); - - test_bin_info_elf(opt_debug_info_dir); - test_bin_info_bundled(opt_debug_info_dir); - test_bin_info_build_id(opt_debug_info_dir); - test_bin_info_debug_link(opt_debug_info_dir); - - status = exit_status(); - -end: - g_option_context_free(context); - - return status; -} diff --git a/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.cpp b/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.cpp new file mode 100644 index 00000000..093de38f --- /dev/null +++ b/tests/plugins/flt.lttng-utils.debug-info/test-bin-info.cpp @@ -0,0 +1,446 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (C) 2015 Antoine Busque + * Copyright (C) 2019 Michael Jeanson + * + * Babeltrace SO info tests + */ + +/* clang-format off */ + +#define BT_LOG_OUTPUT_LEVEL ((bt_logging_level) BT_LOG_WARNING) +#define BT_LOG_TAG "TEST/BIN-INFO" +#include "logging/log.h" + +#include +#include +#include +#include +#include + +#include "common/macros.h" +#include "common/assert.h" +#include + +#include "tap/tap.h" + +#define NR_TESTS 57 + +#define SO_NAME "libhello-so" +#define DEBUG_NAME "libhello-so.debug" +#define FUNC_FOO_FILENAME "./libhello.c" +#define FUNC_FOO_PRINTF_NAME_FMT "foo+0x%" PRIx64 +#define FUNC_FOO_NAME_LEN 64 + +#define DWARF_DIR_NAME "dwarf-full" +#define ELF_DIR_NAME "elf-only" +#define BUILDID_DIR_NAME "build-id" +#define DEBUGLINK_DIR_NAME "debug-link" + +/* Lower bound of PIC address mapping */ +#define SO_LOW_ADDR 0x400000 +/* Size of PIC address mapping */ +#define SO_MEMSZ 0x800000 +/* An address outside the PIC mapping */ +#define SO_INV_ADDR 0x200000 + +#define BUILD_ID_HEX_LEN 20 + +static uint64_t opt_func_foo_addr; +static uint64_t opt_func_foo_printf_offset; +static uint64_t opt_func_foo_printf_line_no; +static uint64_t opt_func_foo_tp_offset; +static uint64_t opt_func_foo_tp_line_no; +static uint64_t opt_debug_link_crc; +static gchar *opt_build_id; +static gchar *opt_debug_info_dir; + +static uint64_t func_foo_printf_addr; +static uint64_t func_foo_tp_addr; +static char func_foo_printf_name[FUNC_FOO_NAME_LEN]; +static uint8_t build_id[BUILD_ID_HEX_LEN]; + +static GOptionEntry entries[] = { + {"foo-addr", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_addr, + "Offset to printf in foo", "0xX"}, + {"printf-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_printf_offset, + "Offset to printf in foo", "0xX"}, + {"printf-lineno", 0, 0, G_OPTION_ARG_INT64, + &opt_func_foo_printf_line_no, "Line number to printf in foo", "N"}, + {"tp-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_offset, + "Offset to tp in foo", "0xX"}, + {"tp-lineno", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_line_no, + "Line number to tp in foo", "N"}, + {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64, &opt_debug_link_crc, + "Debug link CRC", "0xX"}, + {"build-id", 0, 0, G_OPTION_ARG_STRING, &opt_build_id, "Build ID", + "XXXXXXXXXXXXXXX"}, + {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir, + "Debug info directory", NULL}, + {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}}; + +static +int build_id_to_bin(void) +{ + int ret, len, i; + + if (!opt_build_id) { + goto error; + } + + len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2); + if (len != (BUILD_ID_HEX_LEN * 2)) { + goto error; + } + + for (i = 0; i < (len / 2); i++) { + ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]); + if (ret != 1) { + goto error; + } + } + + if (i != BUILD_ID_HEX_LEN) { + goto error; + } + + return 0; +error: + return -1; +} + +static +void subtest_has_address(struct bin_info *bin, uint64_t addr) +{ + int ret; + + ret = bin_info_has_address(bin, SO_LOW_ADDR - 1); + ok(ret == 0, "bin_info_has_address - address under SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR); + ok(ret == 1, "bin_info_has_address - lower bound of SO's range"); + + ret = bin_info_has_address(bin, addr); + ok(ret == 1, "bin_info_has_address - address in SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1); + ok(ret == 1, "bin_info_has_address - upper bound of SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ); + ok(ret == 0, "bin_info_has_address - address above SO's range"); +} + +static +void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr, + char *func_name) +{ + int ret; + char *_func_name = NULL; + + ret = bin_info_lookup_function_name(bin, addr, &_func_name); + ok(ret == 0, "bin_info_lookup_function_name successful at 0x%" PRIx64, addr); + if (_func_name) { + ok(strcmp(_func_name, func_name) == 0, + "bin_info_lookup_function_name - correct function name (%s == %s)", + func_name, _func_name); + free(_func_name); + _func_name = NULL; + } else { + skip(1, + "bin_info_lookup_function_name - function name is NULL"); + } + + /* Test function name lookup - erroneous address */ + ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name); + ok(ret == -1 && !_func_name, + "bin_info_lookup_function_name - fail on invalid addr"); + free(_func_name); +} + +static +void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr, + uint64_t line_no, const char *filename) +{ + int ret; + struct source_location *src_loc = NULL; + + ret = bin_info_lookup_source_location(bin, addr, &src_loc); + ok(ret == 0, "bin_info_lookup_source_location successful at 0x%" PRIx64, + addr); + if (src_loc) { + ok(src_loc->line_no == line_no, + "bin_info_lookup_source_location - correct line_no (%" PRIu64 " == %" PRIu64 ")", + line_no, src_loc->line_no); + ok(strcmp(src_loc->filename, filename) == 0, + "bin_info_lookup_source_location - correct filename (%s == %s)", + filename, src_loc->filename); + source_location_destroy(src_loc); + src_loc = NULL; + } else { + fail("bin_info_lookup_source_location - src_loc is NULL"); + fail("bin_info_lookup_source_location - src_loc is NULL"); + } + + /* Test source location lookup - erroneous address */ + ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc); + ok(ret == -1 && !src_loc, + "bin_info_lookup_source_location - fail on invalid addr"); + if (src_loc) { + source_location_destroy(src_loc); + } +} + +static +void test_bin_info_build_id(const char *bin_info_dir) +{ + int ret; + char *data_dir, *bin_path; + struct bin_info *bin = NULL; + struct bt_fd_cache fdc; + uint8_t invalid_build_id[BUILD_ID_HEX_LEN] = { + 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd, + 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb + }; + + diag("bin-info tests - separate DWARF via build ID"); + + data_dir = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, NULL); + bin_path = + g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL); + + if (!data_dir || !bin_path) { + exit(EXIT_FAILURE); + } + + ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); + ok(bin, "bin_info_create successful (%s)", bin_path); + + /* Test setting invalid build_id */ + ret = bin_info_set_build_id(bin, invalid_build_id, BUILD_ID_HEX_LEN); + ok(ret == -1, "bin_info_set_build_id fail on invalid build_id"); + + /* Test setting correct build_id */ + ret = bin_info_set_build_id(bin, build_id, BUILD_ID_HEX_LEN); + ok(ret == 0, "bin_info_set_build_id successful"); + + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + + /* Test function name lookup (with DWARF) */ + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); + + /* Test source location lookup */ + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); + + bin_info_destroy(bin); + bt_fd_cache_fini(&fdc); + g_free(data_dir); + g_free(bin_path); +} + +static +void test_bin_info_debug_link(const char *bin_info_dir) +{ + int ret; + char *data_dir, *bin_path; + struct bin_info *bin = NULL; + struct bt_fd_cache fdc; + + diag("bin-info tests - separate DWARF via debug link"); + + data_dir = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, NULL); + bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME, + NULL); + + if (!data_dir || !bin_path) { + exit(EXIT_FAILURE); + } + + ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); + ok(bin, "bin_info_create successful (%s)", bin_path); + + /* Test setting debug link */ + ret = bin_info_set_debug_link(bin, DEBUG_NAME, opt_debug_link_crc); + ok(ret == 0, "bin_info_set_debug_link successful"); + + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + + /* Test function name lookup (with DWARF) */ + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); + + /* Test source location lookup */ + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); + + bin_info_destroy(bin); + bt_fd_cache_fini(&fdc); + g_free(data_dir); + g_free(bin_path); +} + +static +void test_bin_info_elf(const char *bin_info_dir) +{ + int ret; + char *data_dir, *bin_path; + struct bin_info *bin = NULL; + struct source_location *src_loc = NULL; + struct bt_fd_cache fdc; + + diag("bin-info tests - ELF only"); + + data_dir = g_build_filename(bin_info_dir, ELF_DIR_NAME, NULL); + bin_path = g_build_filename(bin_info_dir, ELF_DIR_NAME, SO_NAME, NULL); + + if (!data_dir || !bin_path) { + exit(EXIT_FAILURE); + } + + ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); + ok(bin, "bin_info_create successful (%s)", bin_path); + + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + + /* Test function name lookup (with ELF) */ + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); + + /* Test source location location - should fail on ELF only file */ + ret = bin_info_lookup_source_location(bin, func_foo_printf_addr, + &src_loc); + ok(ret == -1, + "bin_info_lookup_source_location - fail on ELF only file"); + + source_location_destroy(src_loc); + bin_info_destroy(bin); + bt_fd_cache_fini(&fdc); + g_free(data_dir); + g_free(bin_path); +} + +static +void test_bin_info_bundled(const char *bin_info_dir) +{ + int ret; + char *data_dir, *bin_path; + struct bin_info *bin = NULL; + struct bt_fd_cache fdc; + + diag("bin-info tests - DWARF bundled in SO file"); + + data_dir = g_build_filename(bin_info_dir, DWARF_DIR_NAME, NULL); + bin_path = + g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL); + + if (!data_dir || !bin_path) { + exit(EXIT_FAILURE); + } + + ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL); + ok(bin, "bin_info_create successful (%s)", bin_path); + + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + + /* Test function name lookup (with DWARF) */ + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); + + /* Test source location lookup */ + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); + + /* Test source location lookup - inlined function */ + subtest_lookup_source_location(bin, func_foo_tp_addr, + opt_func_foo_tp_line_no, + FUNC_FOO_FILENAME); + + bin_info_destroy(bin); + bt_fd_cache_fini(&fdc); + g_free(data_dir); + g_free(bin_path); +} + +int main(int argc, char **argv) +{ + int ret; + GError *error = NULL; + GOptionContext *context; + int status; + + plan_tests(NR_TESTS); + + context = g_option_context_new("- bin info test"); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + fprintf(stderr, "option parsing failed: %s\n", error->message); + status = EXIT_FAILURE; + goto end; + } + + g_snprintf(func_foo_printf_name, FUNC_FOO_NAME_LEN, + FUNC_FOO_PRINTF_NAME_FMT, opt_func_foo_printf_offset); + func_foo_printf_addr = + SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_printf_offset; + func_foo_tp_addr = + SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_tp_offset; + + if (build_id_to_bin()) { + fprintf(stderr, "Failed to parse / missing build id\n"); + status = EXIT_FAILURE; + goto end; + } + + ret = bin_info_init(BT_LOG_OUTPUT_LEVEL, NULL); + ok(ret == 0, "bin_info_init successful"); + + test_bin_info_elf(opt_debug_info_dir); + test_bin_info_bundled(opt_debug_info_dir); + test_bin_info_build_id(opt_debug_info_dir); + test_bin_info_debug_link(opt_debug_info_dir); + + status = exit_status(); + +end: + g_option_context_free(context); + + return status; +} diff --git a/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c b/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c deleted file mode 100644 index e50d1c44..00000000 --- a/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0-only - * - * Copyright (C) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (C) 2015 Antoine Busque - * - * Babeltrace bt_dwarf (DWARF utilities) tests - */ - -#include -#include -#include -#include -#include -#include -#include -#include "tap/tap.h" - -#define NR_TESTS 17 - -#define SO_NAME "libhello-so" -#define DWARF_DIR_NAME "dwarf-full" -#define ELF_DIR_NAME "elf-only" - -/* - * Test that we fail on an ELF file without DWARF. - */ -static -void test_bt_no_dwarf(const char *data_dir) -{ - int fd; - char *path; - Dwarf *dwarf_info = NULL; - - path = g_build_filename(data_dir, ELF_DIR_NAME, SO_NAME, NULL); - if (!path) { - diag("Failed to allocate memory for path"); - exit(EXIT_FAILURE); - } - - fd = open(path, O_RDONLY); - ok(fd >= 0, "Open ELF file %s", path); - if (fd < 0) { - skip(1, "dwarf_begin failed as expected"); - } else { - dwarf_info = dwarf_begin(fd, DWARF_C_READ); - ok(!dwarf_info, "dwarf_begin failed as expected"); - } - - if (dwarf_info) { - dwarf_end(dwarf_info); - } - - if (fd >= 0) { - close(fd); - } - g_free(path); -} - -/* - * Test with a proper ELF file with DWARF. - */ -static -void test_bt_dwarf(const char *data_dir) -{ - int fd, ret, tag = -1; - char *path; - char *die_name = NULL; - struct bt_dwarf_cu *cu = NULL; - struct bt_dwarf_die *die = NULL; - Dwarf *dwarf_info = NULL; - - path = g_build_filename(data_dir, DWARF_DIR_NAME, SO_NAME, NULL); - if (!path) { - diag("Failed to allocate memory for path"); - exit(EXIT_FAILURE); - } - - fd = open(path, O_RDONLY); - ok(fd >= 0, "Open DWARF file %s", path); - if (fd < 0) { - exit(EXIT_FAILURE); - } - dwarf_info = dwarf_begin(fd, DWARF_C_READ); - ok(dwarf_info, "dwarf_begin successful"); - cu = bt_dwarf_cu_create(dwarf_info); - ok(cu, "bt_dwarf_cu_create successful"); - ret = bt_dwarf_cu_next(cu); - ok(ret == 0, "bt_dwarf_cu_next successful"); - die = bt_dwarf_die_create(cu); - ok(die, "bt_dwarf_die_create successful"); - if (!die) { - exit(EXIT_FAILURE); - } - /* - * Test bt_dwarf_die_next twice, as the code path is different - * for DIEs at depth 0 (just created) and other depths. - */ - ret = bt_dwarf_die_next(die); - ok(ret == 0, "bt_dwarf_die_next from root DIE successful"); - ok(die->depth == 1, - "bt_dwarf_die_next from root DIE - correct depth value"); - ret = bt_dwarf_die_next(die); - ok(ret == 0, - "bt_dwarf_die_next from non-root DIE successful"); - ok(die->depth == 1, - "bt_dwarf_die_next from non-root DIE - correct depth value"); - - /* Reset DIE to test dwarf_child */ - bt_dwarf_die_destroy(die); - die = bt_dwarf_die_create(cu); - if (!die) { - diag("Failed to create bt_dwarf_die"); - exit(EXIT_FAILURE); - } - - ret = bt_dwarf_die_child(die); - ok(ret == 0, "bt_dwarf_die_child successful"); - ok(die->depth == 1, "bt_dwarf_die_child - correct depth value"); - - ret = bt_dwarf_die_get_tag(die, &tag); - ok(ret == 0, "bt_dwarf_die_get_tag successful"); - ok(tag == DW_TAG_typedef, "bt_dwarf_die_get_tag - correct tag value"); - ret = bt_dwarf_die_get_name(die, &die_name); - ok(ret == 0, "bt_dwarf_die_get_name successful"); - ok(strcmp(die_name, "size_t") == 0, - "bt_dwarf_die_get_name - correct name value"); - - bt_dwarf_die_destroy(die); - bt_dwarf_cu_destroy(cu); - dwarf_end(dwarf_info); - free(die_name); - close(fd); - g_free(path); -} - -int main(int argc, char **argv) -{ - const char *data_dir; - - plan_tests(NR_TESTS); - - if (argc != 2) { - return EXIT_FAILURE; - } else { - data_dir = argv[1]; - } - - test_bt_no_dwarf(data_dir); - test_bt_dwarf(data_dir); - - return exit_status(); -} diff --git a/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.cpp b/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.cpp new file mode 100644 index 00000000..7ab92f0e --- /dev/null +++ b/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.cpp @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (C) 2015 Antoine Busque + * + * Babeltrace bt_dwarf (DWARF utilities) tests + */ + +/* clang-format off */ + +#include +#include +#include +#include +#include +#include +#include +#include "tap/tap.h" + +#define NR_TESTS 17 + +#define SO_NAME "libhello-so" +#define DWARF_DIR_NAME "dwarf-full" +#define ELF_DIR_NAME "elf-only" + +/* + * Test that we fail on an ELF file without DWARF. + */ +static +void test_bt_no_dwarf(const char *data_dir) +{ + int fd; + char *path; + Dwarf *dwarf_info = NULL; + + path = g_build_filename(data_dir, ELF_DIR_NAME, SO_NAME, NULL); + if (!path) { + diag("Failed to allocate memory for path"); + exit(EXIT_FAILURE); + } + + fd = open(path, O_RDONLY); + ok(fd >= 0, "Open ELF file %s", path); + if (fd < 0) { + skip(1, "dwarf_begin failed as expected"); + } else { + dwarf_info = dwarf_begin(fd, DWARF_C_READ); + ok(!dwarf_info, "dwarf_begin failed as expected"); + } + + if (dwarf_info) { + dwarf_end(dwarf_info); + } + + if (fd >= 0) { + close(fd); + } + g_free(path); +} + +/* + * Test with a proper ELF file with DWARF. + */ +static +void test_bt_dwarf(const char *data_dir) +{ + int fd, ret, tag = -1; + char *path; + char *die_name = NULL; + struct bt_dwarf_cu *cu = NULL; + struct bt_dwarf_die *die = NULL; + Dwarf *dwarf_info = NULL; + + path = g_build_filename(data_dir, DWARF_DIR_NAME, SO_NAME, NULL); + if (!path) { + diag("Failed to allocate memory for path"); + exit(EXIT_FAILURE); + } + + fd = open(path, O_RDONLY); + ok(fd >= 0, "Open DWARF file %s", path); + if (fd < 0) { + exit(EXIT_FAILURE); + } + dwarf_info = dwarf_begin(fd, DWARF_C_READ); + ok(dwarf_info, "dwarf_begin successful"); + cu = bt_dwarf_cu_create(dwarf_info); + ok(cu, "bt_dwarf_cu_create successful"); + ret = bt_dwarf_cu_next(cu); + ok(ret == 0, "bt_dwarf_cu_next successful"); + die = bt_dwarf_die_create(cu); + ok(die, "bt_dwarf_die_create successful"); + if (!die) { + exit(EXIT_FAILURE); + } + /* + * Test bt_dwarf_die_next twice, as the code path is different + * for DIEs at depth 0 (just created) and other depths. + */ + ret = bt_dwarf_die_next(die); + ok(ret == 0, "bt_dwarf_die_next from root DIE successful"); + ok(die->depth == 1, + "bt_dwarf_die_next from root DIE - correct depth value"); + ret = bt_dwarf_die_next(die); + ok(ret == 0, + "bt_dwarf_die_next from non-root DIE successful"); + ok(die->depth == 1, + "bt_dwarf_die_next from non-root DIE - correct depth value"); + + /* Reset DIE to test dwarf_child */ + bt_dwarf_die_destroy(die); + die = bt_dwarf_die_create(cu); + if (!die) { + diag("Failed to create bt_dwarf_die"); + exit(EXIT_FAILURE); + } + + ret = bt_dwarf_die_child(die); + ok(ret == 0, "bt_dwarf_die_child successful"); + ok(die->depth == 1, "bt_dwarf_die_child - correct depth value"); + + ret = bt_dwarf_die_get_tag(die, &tag); + ok(ret == 0, "bt_dwarf_die_get_tag successful"); + ok(tag == DW_TAG_typedef, "bt_dwarf_die_get_tag - correct tag value"); + ret = bt_dwarf_die_get_name(die, &die_name); + ok(ret == 0, "bt_dwarf_die_get_name successful"); + ok(strcmp(die_name, "size_t") == 0, + "bt_dwarf_die_get_name - correct name value"); + + bt_dwarf_die_destroy(die); + bt_dwarf_cu_destroy(cu); + dwarf_end(dwarf_info); + free(die_name); + close(fd); + g_free(path); +} + +int main(int argc, char **argv) +{ + const char *data_dir; + + plan_tests(NR_TESTS); + + if (argc != 2) { + return EXIT_FAILURE; + } else { + data_dir = argv[1]; + } + + test_bt_no_dwarf(data_dir); + test_bt_dwarf(data_dir); + + return exit_status(); +}