From: Francis Deslauriers Date: Wed, 3 Apr 2019 16:56:17 +0000 (-0400) Subject: Cleanup: Move `debug-info` in its own sub-directory X-Git-Tag: v2.0.0-pre5~89 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=61763ad5f7854ae00aef7eed029e7f95179ce6a5 Cleanup: Move `debug-info` in its own sub-directory Signed-off-by: Francis Deslauriers --- diff --git a/configure.ac b/configure.ac index eba84ee5..45c6548c 100644 --- a/configure.ac +++ b/configure.ac @@ -784,6 +784,7 @@ AC_CONFIG_FILES([ plugins/utils/muxer/Makefile python-plugin-provider/Makefile plugins/lttng-utils/Makefile + plugins/lttng-utils/debug-info/Makefile babeltrace.pc babeltrace-ctf.pc ]) diff --git a/plugins/lttng-utils/Makefile.am b/plugins/lttng-utils/Makefile.am index a090390f..34ff2a64 100644 --- a/plugins/lttng-utils/Makefile.am +++ b/plugins/lttng-utils/Makefile.am @@ -1,37 +1,18 @@ -AM_CPPFLAGS += -I$(top_srcdir)/plugins +SUBDIRS = +if ENABLE_DEBUG_INFO +SUBDIRS += debug-info +endif -noinst_LTLIBRARIES = libdebug-info.la -libdebug_info_la_SOURCES = \ - bin-info.c \ - bin-info.h \ - crc32.c \ - crc32.h \ - debug-info.c \ - debug-info.h \ - dwarf.c \ - dwarf.h \ - trace-ir-data-copy.c \ - trace-ir-data-copy.h \ - trace-ir-mapping.c \ - trace-ir-mapping.h \ - trace-ir-metadata-copy.c \ - trace-ir-metadata-copy.h \ - trace-ir-metadata-field-class-copy.c \ - trace-ir-metadata-field-class-copy.h \ - logging.c \ - logging.h +AM_CPPFLAGS += -I$(top_srcdir)/plugins plugindir = "$(PLUGINSDIR)" plugin_LTLIBRARIES = babeltrace-plugin-lttng-utils.la babeltrace_plugin_lttng_utils_la_SOURCES = \ - plugin.c \ - utils.c \ - utils.h \ - logging.h + plugin.c babeltrace_plugin_lttng_utils_la_LIBADD = \ - libdebug-info.la + debug-info/libdebug-info.la babeltrace_plugin_lttng_utils_la_LDFLAGS = \ $(LT_NO_UNDEFINED) \ diff --git a/plugins/lttng-utils/bin-info.c b/plugins/lttng-utils/bin-info.c deleted file mode 100644 index c3e16cec..00000000 --- a/plugins/lttng-utils/bin-info.c +++ /dev/null @@ -1,1565 +0,0 @@ -/* - * bin-info.c - * - * Babeltrace - Executable and Shared Object Debug Info Reader - * - * Copyright 2015 Antoine Busque - * - * Author: Antoine Busque - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO" -#include "logging.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dwarf.h" -#include "bin-info.h" -#include "crc32.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" - -BT_HIDDEN -int bin_info_init(void) -{ - int ret = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) { - BT_LOGD("ELF library initialization failed: %s.", - elf_errmsg(-1)); - ret = -1; - } - - return ret; -} - -BT_HIDDEN -struct bin_info *bin_info_create(const char *path, uint64_t low_addr, - uint64_t memsz, bool is_pic, const char *debug_info_dir, - const char *target_prefix) -{ - struct bin_info *bin = NULL; - - if (!path) { - goto error; - } - - bin = g_new0(struct bin_info, 1); - if (!bin) { - goto error; - } - - if (target_prefix) { - bin->elf_path = g_build_path("/", 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; - - return bin; - -error: - bin_info_destroy(bin); - return NULL; -} - -BT_HIDDEN -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); - - close(bin->elf_fd); - close(bin->dwarf_fd); - - 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) -{ - int elf_fd = -1; - Elf *elf_file = NULL; - - if (!bin) { - goto error; - } - - elf_fd = open(bin->elf_path, O_RDONLY); - if (elf_fd < 0) { - elf_fd = -errno; - BT_LOGE("Failed to open %s\n", bin->elf_path); - goto error; - } - - elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); - if (!elf_file) { - BT_LOGE("elf_begin failed: %s\n", elf_errmsg(-1)); - goto error; - } - - if (elf_kind(elf_file) != ELF_K_ELF) { - BT_LOGE("Error: %s is not an ELF object\n", - bin->elf_path); - goto error; - } - - bin->elf_fd = elf_fd; - bin->elf_file = elf_file; - return 0; - -error: - if (elf_fd >= 0) { - close(elf_fd); - elf_fd = -1; - } - elf_end(elf_file); - return elf_fd; -} - -/** - * From a note section data buffer, check if it is a build id note. - * - * @param buf 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(uint8_t *buf) -{ - int ret = 0; - uint32_t name_sz, desc_sz, note_type; - - /* The note section header has 3 32bit integer for the following: - * - Section name size - * - Description size - * - Note type - */ - name_sz = (uint32_t) *buf; - buf += sizeof(name_sz); - - buf += sizeof(desc_sz); - - note_type = (uint32_t) *buf; - buf += sizeof(note_type); - - /* Check the note type. */ - if (note_type != NT_GNU_BUILD_ID) { - goto invalid; - } - - /* Check the note name. */ - if (memcmp(buf, BUILD_ID_NOTE_NAME, name_sz) != 0) { - goto invalid; - } - - ret = 1; - -invalid: - return ret; -} - -/** - * From a build id note section data buffer, check if the build id it contains - * is identical to the build id passed as parameter. - * - * @param file_build_id_note 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(uint8_t *file_build_id_note, - uint8_t *build_id, size_t build_id_len) -{ - uint32_t name_sz, desc_sz, note_type; - - if (build_id_len <= 0) { - goto end; - } - - /* The note section header has 3 32bit integer for the following: - * - Section name size - * - Description size - * - Note type - */ - name_sz = (uint32_t) *file_build_id_note; - file_build_id_note += sizeof(name_sz); - file_build_id_note += sizeof(desc_sz); - file_build_id_note += sizeof(note_type); - - /* - * Move the pointer pass the name char array. This corresponds to the - * beginning of the description section. The description is the build - * id in the case of a build id note. - */ - file_build_id_note += name_sz; - - /* - * Compare the binary build id with the supplied build id. - */ - if (memcmp(build_id, file_build_id_note, 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 occured. - */ -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; - Elf_Data *note_data = NULL; - GElf_Shdr *curr_section_hdr = NULL; - - 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; - } - } - - curr_section_hdr = g_new0(GElf_Shdr, 1); - if (!curr_section_hdr) { - goto error; - } - - next_section = elf_nextscn(bin->elf_file, curr_section); - if (!next_section) { - goto error; - } - - while (next_section) { - curr_section = next_section; - next_section = elf_nextscn(bin->elf_file, curr_section); - - curr_section_hdr = gelf_getshdr(curr_section, curr_section_hdr); - - if (!curr_section_hdr) { - goto error; - } - - if (curr_section_hdr->sh_type != SHT_NOTE) { - continue; - } - - 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->d_buf); - 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->d_buf, - bin->build_id, bin->build_id_len); - if (!is_matching) { - break; - } - } -error: - g_free(curr_section_hdr); - return is_matching; -} - -BT_HIDDEN -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; - } - - /* 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_LOGD_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; -} - -BT_HIDDEN -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 fd = -1, ret = 0; - struct bt_dwarf_cu *cu = NULL; - Dwarf *dwarf_info = NULL; - - if (!bin || !path) { - goto error; - } - - fd = open(path, O_RDONLY); - if (fd < 0) { - fd = -errno; - goto error; - } - - dwarf_info = dwarf_begin(fd, 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_fd = fd; - bin->dwarf_path = g_strdup(path); - if (!bin->dwarf_path) { - goto error; - } - bin->dwarf_info = dwarf_info; - free(cu); - - return 0; - -error: - if (fd >= 0) { - close(fd); - fd = -1; - } - dwarf_end(dwarf_info); - g_free(dwarf_info); - free(cu); - - return fd; -} - -/** - * 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_file = NULL; - const char *dbg_dir = NULL; - size_t build_id_file_len; - - if (!bin || !bin->build_id) { - goto error; - } - - dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; - - /* 2 characters per byte printed in hex, +1 for '/' and +1 for '\0' */ - build_id_file_len = (2 * bin->build_id_len) + 1 + - strlen(BUILD_ID_SUFFIX) + 1; - build_id_file = g_new0(gchar, build_id_file_len); - if (!build_id_file) { - goto error; - } - - g_snprintf(build_id_file, 4, "%02x/", bin->build_id[0]); - for (i = 1; i < bin->build_id_len; ++i) { - int path_idx = 3 + 2 * (i - 1); - - g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); - } - g_strconcat(build_id_file, BUILD_ID_SUFFIX, NULL); - - path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, 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: - free(build_id_file); - 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(char *path, uint32_t crc) -{ - int ret = 0, fd = -1; - uint32_t _crc = 0; - - if (!path) { - goto end_noclose; - } - - fd = open(path, O_RDONLY); - if (fd < 0) { - goto end_noclose; - } - - ret = crc32(fd, &_crc); - if (ret) { - ret = 0; - goto end; - } - - ret = (crc == _crc); - -end: - close(fd); -end_noclose: - 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, *dir_name = NULL, *path = NULL; - - if (!bin || !bin->dbg_link_filename) { - goto error; - } - - dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; - dir_name = g_path_get_dirname(bin->elf_path); - if (!dir_name) { - goto error; - } - - bin_dir = g_strconcat(dir_name, "/", NULL); - - /* First look in the executable's dir */ - path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL); - - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - - /* If not found, look in .debug subdir */ - g_free(path); - path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); - - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - - /* Lastly, look under the global debug directory */ - g_free(path); - - path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - -error: - ret = -1; -end: - g_free(dir_name); - 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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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_LOGD_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_LOGD("Failed to lookup function name (ELF): " - "ret=%d", ret); - } - } else { - ret = bin_info_lookup_dwarf_function_name(bin, addr, - &_func_name); - if (ret) { - BT_LOGD("Failed to lookup function name (DWARF): " - "ret=%d", ret); - } - } - - *func_name = _func_name; - return 0; - -error: - return -1; -} - -BT_HIDDEN -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 - * @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, 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) { - goto error; - } - - 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); - } - - bt_dwarf_die_destroy(die); - - if (_src_loc) { - *src_loc = _src_loc; - } - - return 0; - -error: - source_location_destroy(_src_loc); - bt_dwarf_die_destroy(die); - return -1; -} - -/** - * 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; -} - -BT_HIDDEN -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/plugins/lttng-utils/bin-info.h b/plugins/lttng-utils/bin-info.h deleted file mode 100644 index 2bcd9fae..00000000 --- a/plugins/lttng-utils/bin-info.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef _BABELTRACE_BIN_INFO_H -#define _BABELTRACE_BIN_INFO_H - -/* - * Babeltrace - Executable and Shared Object Debug Info Reader - * - * Copyright 2015 Antoine Busque - * - * Author: Antoine Busque - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#define DEFAULT_DEBUG_DIR "/usr/lib/debug" -#define DEBUG_SUBDIR ".debug/" -#define BUILD_ID_SUBDIR ".build-id/" -#define BUILD_ID_SUFFIX ".debug" - -struct bin_info { - /* 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; - /* FDs to ELF and DWARF files. */ - int elf_fd; - int dwarf_fd; - /* 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; -}; - -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 - */ -BT_HIDDEN -int bin_info_init(void); - -/** - * 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. - */ -BT_HIDDEN -struct bin_info *bin_info_create(const char *path, uint64_t low_addr, - uint64_t memsz, bool is_pic, const char *debug_info_dir, - const char *target_prefix); - -/** - * Destroy the given bin_info instance - * - * @param bin bin_info instance to destroy - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -void source_location_destroy(struct source_location *src_loc); - -#endif /* _BABELTRACE_BIN_INFO_H */ diff --git a/plugins/lttng-utils/crc32.c b/plugins/lttng-utils/crc32.c deleted file mode 100644 index e68c0434..00000000 --- a/plugins/lttng-utils/crc32.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "crc32.h" - -#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) - -/* generated using the AUTODIN II polynomial - * x^32 + x^26 + x^23 + x^22 + x^16 + - * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 - */ -static const uint32_t crctab[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; - -int crc32(int fd, uint32_t *crc) -{ - int nr; - uint32_t _crc = ~0; - char buf[BUFSIZ], *p; - - if (fd < 0 || !crc) { - goto error; - } - - while ((nr = read(fd, buf, sizeof(buf))) > 0) { - for (p = buf; nr--; ++p) { - CRC(_crc, *p); - } - } - - if (nr < 0) { - goto error; - } - - *crc = ~_crc; - return 0; - -error: - return -1; -} diff --git a/plugins/lttng-utils/crc32.h b/plugins/lttng-utils/crc32.h deleted file mode 100644 index 4a229d63..00000000 --- a/plugins/lttng-utils/crc32.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _BABELTRACE_CRC32_H -#define _BABELTRACE_CRC32_H - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -/** - * Compute a 32-bit cyclic redundancy checksum for a given file. - * - * On success, the out parameter crc is set with the computed checksum - * value, - * - * @param fd File descriptor for the file for which to compute the CRC - * @param crc Out parameter, the computed checksum - * @returns 0 on success, -1 on failure. - */ -BT_HIDDEN -int crc32(int fd, uint32_t *crc); - -#endif /* _BABELTRACE_CRC32_H */ diff --git a/plugins/lttng-utils/debug-info.c b/plugins/lttng-utils/debug-info.c deleted file mode 100644 index d84bf397..00000000 --- a/plugins/lttng-utils/debug-info.c +++ /dev/null @@ -1,2055 +0,0 @@ -/* - * Babeltrace - Debug Information State Tracker - * - * 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 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT" -#include "logging.h" - -#include -#include - -#include -#include - -#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" - -#define DEFAULT_DEBUG_INFO_FIELD_NAME "debug_info" -#define LTTNG_UST_STATEDUMP_PREFIX "lttng_ust" -#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" - -struct debug_info_component { - gchar *arg_debug_dir; - gchar *arg_debug_info_field_name; - gchar *arg_target_prefix; - bt_bool arg_full_path; -}; - -struct debug_info_msg_iter { - struct debug_info_component *debug_info_component; - bt_self_message_iterator *input_iterator; - bt_self_component *self_comp; - bt_self_component_port_input_message_iterator *msg_iter; - - struct trace_ir_maps *ir_maps; - /* in_trace -> debug_info_mapping. */ - GHashTable *debug_info_map; -}; - -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 { - struct debug_info_component *comp; - const bt_trace *input_trace; - uint64_t 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; -}; - -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(); -} - -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) -{ - int ret; - struct debug_info_source *debug_info_src = NULL; - struct source_location *src_loc = NULL; - - 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_LOGD("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_LOGD("Error occured 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(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_signed_integer_get_value( - event_borrow_common_context_field(event, field_name)); -} - -static inline -int 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); - 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); - - return 0; -} - -static inline -int 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; - int ret; - - ret = 0; - - 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); - 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_unsigned_integer_get_value(curr_field); - } - - return ret; -} - -static -void event_get_payload_unsigned_integer_field_value(const bt_event *event, - const char *field_name, uint64_t *value) -{ - *value = bt_field_unsigned_integer_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) != NULL; -} - -static -struct debug_info_source *proc_debug_info_sources_get_entry( - 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); - 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; -} - -BT_HIDDEN -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(proc_dbg_info_src, ip); - -end: - return dbg_info_src; -} - -BT_HIDDEN -struct debug_info *debug_info_create(struct debug_info_component *comp, - const bt_trace *trace) -{ - int ret; - struct debug_info *debug_info; - - debug_info = g_new0(struct debug_info, 1); - if (!debug_info) { - goto end; - } - - 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; - -end: - return debug_info; -error: - g_free(debug_info); - return NULL; -} - -BT_HIDDEN -void debug_info_destroy(struct debug_info *debug_info) -{ - bt_trace_status status; - if (!debug_info) { - goto end; - } - - if (debug_info->vpid_to_proc_dbg_info_src) { - g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src); - } - - status = bt_trace_remove_destruction_listener(debug_info->input_trace, - debug_info->destruction_listener_id); - if (status != BT_TRACE_STATUS_OK) { - BT_LOGD("Trace destruction listener removal failed."); - } - - 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; - } - ret = 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; - } - - ret = event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME, - build_id); - if (ret) { - goto end; - } - - 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(path, baddr, memsz, is_pic, - debug_info->comp->arg_debug_dir, - debug_info->comp->arg_target_prefix); - 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; -} - -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) { - debug_info = debug_info_create(debug_it->debug_info_component, - trace); - g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace, - debug_info); - bt_trace_add_destruction_listener(trace, - trace_debug_info_remove_func, debug_it, - &debug_info->destruction_listener_id); - } - - 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_field_status status; - - BT_ASSERT(bt_field_get_class_type(curr_field) == - BT_FIELD_CLASS_TYPE_STRING); - - if (dbg_info_src) { - if (full_path) { - status = bt_field_string_set_value(curr_field, - dbg_info_src->bin_path); - } else { - status = bt_field_string_set_value(curr_field, - dbg_info_src->short_bin_path); - } - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set path component of \"bin\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - - status = bt_field_string_append(curr_field, ":"); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set colon component of \"bin\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - - status = bt_field_string_append(curr_field, dbg_info_src->bin_loc); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set bin location component of \"bin\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - } else { - status = bt_field_string_set_value(curr_field, ""); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set \"bin\" curr_field field's value: " - "str-fc-addr=%p", curr_field); - } - } -} - -static -void fill_debug_info_func_field(struct debug_info_source *dbg_info_src, - bt_field *curr_field) -{ - bt_field_status status; - - BT_ASSERT(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_STATUS_OK) { - BT_LOGE("Cannot set \"func\" curr_field field's value: " - "str-fc-addr=%p", curr_field); - } -} - -static -void fill_debug_info_src_field(struct debug_info_source *dbg_info_src, - bool full_path, bt_field *curr_field) -{ - bt_field_status status; - - BT_ASSERT(bt_field_get_class_type(curr_field) == - BT_FIELD_CLASS_TYPE_STRING); - - if (dbg_info_src && dbg_info_src->src_path) { - if (full_path) { - status = bt_field_string_set_value(curr_field, - dbg_info_src->src_path); - } else { - status = bt_field_string_set_value(curr_field, - dbg_info_src->short_src_path); - } - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set path component of \"src\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - - status = bt_field_string_append(curr_field, ":"); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set colon component of \"src\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - - status = bt_field_string_append(curr_field, dbg_info_src->line_no); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set line number component of \"src\" " - "curr_field field's value: str-fc-addr=%p", - curr_field); - } - } else { - status = bt_field_string_set_value(curr_field, ""); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set \"src\" curr_field field's value: " - "str-fc-addr=%p", curr_field); - } - } -} - -void fill_debug_info_field_empty(bt_field *debug_info_field) -{ - bt_field_status status; - bt_field *bin_field, *func_field, *src_field; - - BT_ASSERT(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(bt_field_get_class_type(bin_field) == - BT_FIELD_CLASS_TYPE_STRING); - BT_ASSERT(bt_field_get_class_type(func_field) == - BT_FIELD_CLASS_TYPE_STRING); - BT_ASSERT(bt_field_get_class_type(src_field) == - BT_FIELD_CLASS_TYPE_STRING); - - status = bt_field_string_set_value(bin_field, ""); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set \"bin\" bin_field field's value: " - "str-fc-addr=%p", bin_field); - } - - status = bt_field_string_set_value(func_field, ""); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set \"func\" func_field field's value: " - "str-fc-addr=%p", func_field); - } - - status = bt_field_string_set_value(src_field, ""); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set \"src\" src_field field's value: " - "str-fc-addr=%p", src_field); - } -} -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(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(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")); - fill_debug_info_func_field(dbg_info_src, - bt_field_structure_borrow_member_field_by_name( - debug_info_field, "func")); - 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")); -} - -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; - - 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_signed_integer_get_value(vpid_field); - ip = bt_field_unsigned_integer_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_LOGD("No debug information for this trace. Setting debug " - "info fields to empty strings."); - fill_debug_info_field_empty(out_debug_info_field); - } -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; - bt_clock_snapshot_state cs_state; - bt_event_class *out_event_class; - bt_packet *out_packet; - bt_event *out_event; - - 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(out_event_class); - - /* Borrow the input and output packets. */ - in_packet = bt_event_borrow_packet_const(in_event); - 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_state = - bt_message_event_borrow_default_clock_snapshot_const( - in_message, &cs); - - /* Create an output event message. */ - BT_ASSERT (cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); - out_message = bt_message_event_create_with_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(debug_it->input_iterator, - out_event_class, out_packet); - } - - if (!out_message) { - BT_LOGE("Error creating output event message."); - goto error; - } - - out_event = bt_message_event_borrow_event(out_message); - - /* Copy the original fields to the output event. */ - copy_event_content(in_event, out_event); - - /* - * 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); - -error: - 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; - - 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_LOGE("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; - - 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_LOGE("Error creating output stream end message: out-s-addr=%p", - out_stream); - } - - /* Remove stream from trace mapping hashtable. */ - trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream); - - return out_message; -} - -static -bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_clock_class *default_cc; - bt_clock_snapshot_state cs_state; - const bt_clock_snapshot *cs; - bt_message *out_message = NULL; - bt_packet *out_packet; - - 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); - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const( - bt_packet_borrow_stream_const(in_packet))); - if (default_cc) { - /* Borrow clock snapshot. */ - cs_state = - bt_message_packet_beginning_borrow_default_clock_snapshot_const( - in_message, &cs); - - /* Create an output packet beginning message. */ - BT_ASSERT(cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); - 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_LOGE("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) -{ - const bt_clock_snapshot *cs; - const bt_packet *in_packet; - const bt_clock_class *default_cc; - bt_clock_snapshot_state cs_state; - bt_message *out_message = NULL; - bt_packet *out_packet; - - 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); - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const( - bt_packet_borrow_stream_const(in_packet))); - if (default_cc) { - /* Borrow clock snapshot. */ - cs_state = - bt_message_packet_end_borrow_default_clock_snapshot_const( - in_message, &cs); - - /* Create an outpute packet end message. */ - BT_ASSERT(cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); - 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_LOGE("Error creating output packet end message: " - "out-p-addr=%p", out_packet); - } - - /* Remove packet from data mapping hashtable. */ - trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet); - - return out_message; -} - -static -bt_message *handle_msg_iterator_inactivity(struct debug_info_msg_iter *debug_it, - 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_stream_act_begin_message(struct debug_info_msg_iter *debug_it, - const bt_message *in_message) -{ - const bt_clock_snapshot *cs; - const bt_clock_class *default_cc; - bt_message *out_message = NULL; - bt_stream *out_stream; - uint64_t cs_value; - bt_message_stream_activity_clock_snapshot_state cs_state; - - const bt_stream *in_stream = - bt_message_stream_activity_beginning_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); - - out_message = bt_message_stream_activity_beginning_create( - debug_it->input_iterator, out_stream); - if (!out_message) { - BT_LOGE("Error creating output stream activity beginning " - "message: out-s-addr=%p", out_stream); - goto error; - } - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const(in_stream)); - if (default_cc) { - /* Borrow clock snapshot. */ - cs_state = - bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const( - in_message, &cs); - - if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) { - cs_value = bt_clock_snapshot_get_value(cs); - bt_message_stream_activity_beginning_set_default_clock_snapshot( - out_message, cs_value); - } else { - bt_message_stream_activity_beginning_set_default_clock_snapshot_state( - out_message, cs_state); - } - } - -error: - return out_message; -} - -static -bt_message *handle_stream_act_end_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_stream *in_stream; - bt_message *out_message; - bt_stream *out_stream; - uint64_t cs_value; - bt_message_stream_activity_clock_snapshot_state cs_state; - - in_stream = bt_message_stream_activity_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); - - out_message = bt_message_stream_activity_end_create( - debug_it->input_iterator, out_stream); - if (!out_message) { - BT_LOGE("Error creating output stream activity end message: " - "out-s-addr=%p", out_stream); - goto error; - } - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const(in_stream)); - - if (default_cc) { - cs_state = - bt_message_stream_activity_end_borrow_default_clock_snapshot_const( - in_message, &cs); - - if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN ) { - cs_value = bt_clock_snapshot_get_value(cs); - bt_message_stream_activity_end_set_default_clock_snapshot( - out_message, cs_value); - } else { - bt_message_stream_activity_end_set_default_clock_snapshot_state( - out_message, cs_state); - } - } - -error: - return out_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; - const bt_clock_class *default_cc; - uint64_t discarded_events, begin_cs_value, end_cs_value; - bt_clock_snapshot_state begin_cs_state, end_cs_state; - bt_property_availability prop_avail; - bt_message *out_message = NULL; - bt_stream *out_stream; - - 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); - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const(in_stream)); - if (default_cc) { - begin_cs_state = - bt_message_discarded_events_borrow_default_beginning_clock_snapshot_const( - in_message, &begin_cs); - end_cs_state = - bt_message_discarded_events_borrow_default_end_clock_snapshot_const( - in_message, &end_cs); - /* - * Both clock snapshots should be known as we check that the - * all input stream classes have an always known clock. Unknown - * clock is not yet supported. - */ - BT_ASSERT(begin_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN && - end_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); - - 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_LOGE("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; - const bt_clock_class *default_cc; - const bt_stream *in_stream; - uint64_t discarded_packets, begin_cs_value, end_cs_value; - bt_clock_snapshot_state begin_cs_state, end_cs_state; - bt_property_availability prop_avail; - bt_message *out_message = NULL; - bt_stream *out_stream; - - 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); - - default_cc = bt_stream_class_borrow_default_clock_class_const( - bt_stream_borrow_class_const(in_stream)); - if (default_cc) { - begin_cs_state = - bt_message_discarded_packets_borrow_default_beginning_clock_snapshot_const( - in_message, &begin_cs); - - end_cs_state = - bt_message_discarded_packets_borrow_default_end_clock_snapshot_const( - in_message, &end_cs); - - /* - * Both clock snapshots should be known as we check that the - * all input stream classes have an always known clock. Unknown - * clock is not yet supported. - */ - BT_ASSERT(begin_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN && - end_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); - - 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_LOGE("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(debug_it, - in_message); - break; - case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING: - out_message = handle_stream_act_begin_message(debug_it, - in_message); - break; - case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END: - out_message = handle_stream_act_end_message(debug_it, - 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: - abort(); - break; - } - - return out_message; -} - -static -int init_from_params(struct debug_info_component *debug_info_component, - const bt_value *params) -{ - const bt_value *value = NULL; - int ret = 0; - - 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; - } - - return ret; -} - -BT_HIDDEN -bt_self_component_status debug_info_comp_init( - bt_self_component_filter *self_comp, - const bt_value *params, UNUSED_VAR void *init_method_data) -{ - int ret; - struct debug_info_component *debug_info_comp; - bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK; - - BT_LOGD("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_LOGE_STR("Failed to allocate one debug_info component."); - goto error; - } - - bt_self_component_set_data( - bt_self_component_filter_as_self_component(self_comp), - debug_info_comp); - - status = bt_self_component_filter_add_input_port(self_comp, "in", - NULL, NULL); - if (status != BT_SELF_COMPONENT_STATUS_OK) { - goto error; - } - - status = bt_self_component_filter_add_output_port(self_comp, "out", - NULL, NULL); - if (status != BT_SELF_COMPONENT_STATUS_OK) { - goto error; - } - - ret = init_from_params(debug_info_comp, params); - if (ret) { - BT_LOGE("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( - bt_self_component_filter_as_self_component(self_comp), - NULL); - - if (status == BT_SELF_COMPONENT_STATUS_OK) { - status = BT_SELF_COMPONENT_STATUS_ERROR; - } -end: - return status; -} - -BT_HIDDEN -void debug_info_comp_finalize(bt_self_component_filter *self_comp) -{ - struct debug_info_component *debug_info = - bt_self_component_get_data( - bt_self_component_filter_as_self_component( - self_comp)); - BT_LOGD("Finalizing debug_info self_component: comp-addr=%p", - self_comp); - - destroy_debug_info_comp(debug_info); -} - -BT_HIDDEN -bt_self_message_iterator_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_self_component_port_input_message_iterator *upstream_iterator = NULL; - bt_message_iterator_status upstream_iterator_ret_status; - struct debug_info_msg_iter *debug_info_msg_iter; - struct debug_info_component *debug_info = NULL; - bt_self_message_iterator_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_SELF_MESSAGE_ITERATOR_STATUS_OK; - - self_comp = bt_self_message_iterator_borrow_component(self_msg_iter); - BT_ASSERT(self_comp); - - debug_info = bt_self_component_get_data(self_comp); - BT_ASSERT(debug_info); - - debug_info_msg_iter = bt_self_message_iterator_get_data(self_msg_iter); - BT_ASSERT(debug_info_msg_iter); - - upstream_iterator = debug_info_msg_iter->msg_iter; - BT_ASSERT(upstream_iterator); - - upstream_iterator_ret_status = - bt_self_component_port_input_message_iterator_next( - upstream_iterator, &input_msgs, count); - if (upstream_iterator_ret_status != BT_MESSAGE_ITERATOR_STATUS_OK) { - /* - * No messages were returned. Not necessarily an error. Convert - * the upstream message iterator status to a self status. - */ - status = bt_common_message_iterator_status_to_self( - upstream_iterator_ret_status); - goto end; - } - - /* - * There should never be more received messages than the capacity we - * provided. - */ - BT_ASSERT(*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]); - } - - status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; -end: - return status; -} - -BT_HIDDEN -bt_self_message_iterator_status debug_info_msg_iter_init( - bt_self_message_iterator *self_msg_iter, - bt_self_component_filter *self_comp, - bt_self_component_port_output *self_port) -{ - bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK; - struct bt_self_component_port_input *input_port; - bt_self_component_port_input_message_iterator *upstream_iterator; - struct debug_info_msg_iter *debug_info_msg_iter; - gchar *debug_info_field_name; - - /* Borrow the upstream input port. */ - input_port = bt_self_component_filter_borrow_input_port_by_name( - self_comp, "in"); - if (!input_port) { - status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR; - goto end; - } - - /* Create an iterator on the upstream component. */ - upstream_iterator = bt_self_component_port_input_message_iterator_create( - input_port); - if (!upstream_iterator) { - status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; - goto end; - } - - debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1); - if (!debug_info_msg_iter) { - status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; - goto end; - } - - /* Create hashtable to 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) { - g_free(debug_info_msg_iter); - status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; - goto end; - } - - debug_info_msg_iter->self_comp = - bt_self_component_filter_as_self_component(self_comp); - - BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF( - debug_info_msg_iter->msg_iter, upstream_iterator); - - debug_info_msg_iter->debug_info_component = bt_self_component_get_data( - bt_self_component_filter_as_self_component( - self_comp)); - - 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( - bt_self_component_filter_as_self_component(self_comp), - debug_info_field_name); - if (!debug_info_msg_iter->ir_maps) { - g_hash_table_destroy(debug_info_msg_iter->debug_info_map); - g_free(debug_info_msg_iter); - status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; - goto end; - } - - bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter); - - debug_info_msg_iter->input_iterator = self_msg_iter; - -end: - return status; -} - -BT_HIDDEN -bt_bool debug_info_msg_iter_can_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_ASSERT(debug_info_msg_iter); - - return bt_self_component_port_input_message_iterator_can_seek_beginning( - debug_info_msg_iter->msg_iter); -} - -BT_HIDDEN -bt_self_message_iterator_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_status status = BT_MESSAGE_ITERATOR_STATUS_OK; - - BT_ASSERT(debug_info_msg_iter); - - /* Ask the upstream component to seek to the beginning. */ - status = bt_self_component_port_input_message_iterator_seek_beginning( - debug_info_msg_iter->msg_iter); - if (status != BT_MESSAGE_ITERATOR_STATUS_OK) { - 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 bt_common_message_iterator_status_to_self(status); -} - -BT_HIDDEN -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); - - bt_self_component_port_input_message_iterator_put_ref( - debug_info_msg_iter->msg_iter); - - trace_ir_maps_destroy(debug_info_msg_iter->ir_maps); - g_hash_table_destroy(debug_info_msg_iter->debug_info_map); - - g_free(debug_info_msg_iter); -} diff --git a/plugins/lttng-utils/debug-info.h b/plugins/lttng-utils/debug-info.h deleted file mode 100644 index bfdbccc1..00000000 --- a/plugins/lttng-utils/debug-info.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_H - -/* - * Babeltrace - Debug information Plugin - * - * Copyright (c) 2015-2019 EfficiOS Inc. - * Copyright (c) 2015 Antoine Busque - * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include - -#define VPID_FIELD_NAME "vpid" -#define IP_FIELD_NAME "ip" - -BT_HIDDEN -bt_self_component_status debug_info_comp_init( - bt_self_component_filter *self_comp, - const bt_value *params, void *init_method_data); - -BT_HIDDEN -void debug_info_comp_finalize(bt_self_component_filter *self_comp); - -BT_HIDDEN -bt_self_message_iterator_status debug_info_msg_iter_init( - bt_self_message_iterator *self_msg_iter, - bt_self_component_filter *self_comp, - bt_self_component_port_output *self_port); - -BT_HIDDEN -bt_self_message_iterator_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_HIDDEN -bt_bool debug_info_msg_iter_can_seek_beginning( - bt_self_message_iterator *message_iterator); - -BT_HIDDEN -bt_self_message_iterator_status debug_info_msg_iter_seek_beginning( - bt_self_message_iterator *message_iterator); - -BT_HIDDEN -void debug_info_msg_iter_finalize(bt_self_message_iterator *it); - -#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */ diff --git a/plugins/lttng-utils/debug-info/Makefile.am b/plugins/lttng-utils/debug-info/Makefile.am new file mode 100644 index 00000000..f43feac6 --- /dev/null +++ b/plugins/lttng-utils/debug-info/Makefile.am @@ -0,0 +1,24 @@ +AM_CPPFLAGS += -I$(top_srcdir)/plugins + +noinst_LTLIBRARIES = libdebug-info.la +libdebug_info_la_SOURCES = \ + bin-info.c \ + bin-info.h \ + crc32.c \ + crc32.h \ + debug-info.c \ + debug-info.h \ + dwarf.c \ + dwarf.h \ + logging.c \ + logging.h \ + trace-ir-data-copy.c \ + trace-ir-data-copy.h \ + trace-ir-mapping.c \ + trace-ir-mapping.h \ + trace-ir-metadata-copy.c \ + trace-ir-metadata-copy.h \ + trace-ir-metadata-field-class-copy.c \ + trace-ir-metadata-field-class-copy.h \ + utils.c \ + utils.h diff --git a/plugins/lttng-utils/debug-info/bin-info.c b/plugins/lttng-utils/debug-info/bin-info.c new file mode 100644 index 00000000..c3e16cec --- /dev/null +++ b/plugins/lttng-utils/debug-info/bin-info.c @@ -0,0 +1,1565 @@ +/* + * bin-info.c + * + * Babeltrace - Executable and Shared Object Debug Info Reader + * + * Copyright 2015 Antoine Busque + * + * Author: Antoine Busque + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dwarf.h" +#include "bin-info.h" +#include "crc32.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" + +BT_HIDDEN +int bin_info_init(void) +{ + int ret = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) { + BT_LOGD("ELF library initialization failed: %s.", + elf_errmsg(-1)); + ret = -1; + } + + return ret; +} + +BT_HIDDEN +struct bin_info *bin_info_create(const char *path, uint64_t low_addr, + uint64_t memsz, bool is_pic, const char *debug_info_dir, + const char *target_prefix) +{ + struct bin_info *bin = NULL; + + if (!path) { + goto error; + } + + bin = g_new0(struct bin_info, 1); + if (!bin) { + goto error; + } + + if (target_prefix) { + bin->elf_path = g_build_path("/", 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; + + return bin; + +error: + bin_info_destroy(bin); + return NULL; +} + +BT_HIDDEN +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); + + close(bin->elf_fd); + close(bin->dwarf_fd); + + 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) +{ + int elf_fd = -1; + Elf *elf_file = NULL; + + if (!bin) { + goto error; + } + + elf_fd = open(bin->elf_path, O_RDONLY); + if (elf_fd < 0) { + elf_fd = -errno; + BT_LOGE("Failed to open %s\n", bin->elf_path); + goto error; + } + + elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); + if (!elf_file) { + BT_LOGE("elf_begin failed: %s\n", elf_errmsg(-1)); + goto error; + } + + if (elf_kind(elf_file) != ELF_K_ELF) { + BT_LOGE("Error: %s is not an ELF object\n", + bin->elf_path); + goto error; + } + + bin->elf_fd = elf_fd; + bin->elf_file = elf_file; + return 0; + +error: + if (elf_fd >= 0) { + close(elf_fd); + elf_fd = -1; + } + elf_end(elf_file); + return elf_fd; +} + +/** + * From a note section data buffer, check if it is a build id note. + * + * @param buf 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(uint8_t *buf) +{ + int ret = 0; + uint32_t name_sz, desc_sz, note_type; + + /* The note section header has 3 32bit integer for the following: + * - Section name size + * - Description size + * - Note type + */ + name_sz = (uint32_t) *buf; + buf += sizeof(name_sz); + + buf += sizeof(desc_sz); + + note_type = (uint32_t) *buf; + buf += sizeof(note_type); + + /* Check the note type. */ + if (note_type != NT_GNU_BUILD_ID) { + goto invalid; + } + + /* Check the note name. */ + if (memcmp(buf, BUILD_ID_NOTE_NAME, name_sz) != 0) { + goto invalid; + } + + ret = 1; + +invalid: + return ret; +} + +/** + * From a build id note section data buffer, check if the build id it contains + * is identical to the build id passed as parameter. + * + * @param file_build_id_note 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(uint8_t *file_build_id_note, + uint8_t *build_id, size_t build_id_len) +{ + uint32_t name_sz, desc_sz, note_type; + + if (build_id_len <= 0) { + goto end; + } + + /* The note section header has 3 32bit integer for the following: + * - Section name size + * - Description size + * - Note type + */ + name_sz = (uint32_t) *file_build_id_note; + file_build_id_note += sizeof(name_sz); + file_build_id_note += sizeof(desc_sz); + file_build_id_note += sizeof(note_type); + + /* + * Move the pointer pass the name char array. This corresponds to the + * beginning of the description section. The description is the build + * id in the case of a build id note. + */ + file_build_id_note += name_sz; + + /* + * Compare the binary build id with the supplied build id. + */ + if (memcmp(build_id, file_build_id_note, 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 occured. + */ +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; + Elf_Data *note_data = NULL; + GElf_Shdr *curr_section_hdr = NULL; + + 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; + } + } + + curr_section_hdr = g_new0(GElf_Shdr, 1); + if (!curr_section_hdr) { + goto error; + } + + next_section = elf_nextscn(bin->elf_file, curr_section); + if (!next_section) { + goto error; + } + + while (next_section) { + curr_section = next_section; + next_section = elf_nextscn(bin->elf_file, curr_section); + + curr_section_hdr = gelf_getshdr(curr_section, curr_section_hdr); + + if (!curr_section_hdr) { + goto error; + } + + if (curr_section_hdr->sh_type != SHT_NOTE) { + continue; + } + + 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->d_buf); + 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->d_buf, + bin->build_id, bin->build_id_len); + if (!is_matching) { + break; + } + } +error: + g_free(curr_section_hdr); + return is_matching; +} + +BT_HIDDEN +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; + } + + /* 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_LOGD_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; +} + +BT_HIDDEN +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 fd = -1, ret = 0; + struct bt_dwarf_cu *cu = NULL; + Dwarf *dwarf_info = NULL; + + if (!bin || !path) { + goto error; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + fd = -errno; + goto error; + } + + dwarf_info = dwarf_begin(fd, 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_fd = fd; + bin->dwarf_path = g_strdup(path); + if (!bin->dwarf_path) { + goto error; + } + bin->dwarf_info = dwarf_info; + free(cu); + + return 0; + +error: + if (fd >= 0) { + close(fd); + fd = -1; + } + dwarf_end(dwarf_info); + g_free(dwarf_info); + free(cu); + + return fd; +} + +/** + * 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_file = NULL; + const char *dbg_dir = NULL; + size_t build_id_file_len; + + if (!bin || !bin->build_id) { + goto error; + } + + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; + + /* 2 characters per byte printed in hex, +1 for '/' and +1 for '\0' */ + build_id_file_len = (2 * bin->build_id_len) + 1 + + strlen(BUILD_ID_SUFFIX) + 1; + build_id_file = g_new0(gchar, build_id_file_len); + if (!build_id_file) { + goto error; + } + + g_snprintf(build_id_file, 4, "%02x/", bin->build_id[0]); + for (i = 1; i < bin->build_id_len; ++i) { + int path_idx = 3 + 2 * (i - 1); + + g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); + } + g_strconcat(build_id_file, BUILD_ID_SUFFIX, NULL); + + path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, 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: + free(build_id_file); + 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(char *path, uint32_t crc) +{ + int ret = 0, fd = -1; + uint32_t _crc = 0; + + if (!path) { + goto end_noclose; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + goto end_noclose; + } + + ret = crc32(fd, &_crc); + if (ret) { + ret = 0; + goto end; + } + + ret = (crc == _crc); + +end: + close(fd); +end_noclose: + 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, *dir_name = NULL, *path = NULL; + + if (!bin || !bin->dbg_link_filename) { + goto error; + } + + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; + dir_name = g_path_get_dirname(bin->elf_path); + if (!dir_name) { + goto error; + } + + bin_dir = g_strconcat(dir_name, "/", NULL); + + /* First look in the executable's dir */ + path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL); + + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + + /* If not found, look in .debug subdir */ + g_free(path); + path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); + + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + + /* Lastly, look under the global debug directory */ + g_free(path); + + path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + +error: + ret = -1; +end: + g_free(dir_name); + 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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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_LOGD_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_LOGD("Failed to lookup function name (ELF): " + "ret=%d", ret); + } + } else { + ret = bin_info_lookup_dwarf_function_name(bin, addr, + &_func_name); + if (ret) { + BT_LOGD("Failed to lookup function name (DWARF): " + "ret=%d", ret); + } + } + + *func_name = _func_name; + return 0; + +error: + return -1; +} + +BT_HIDDEN +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 + * @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, 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) { + goto error; + } + + 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); + } + + bt_dwarf_die_destroy(die); + + if (_src_loc) { + *src_loc = _src_loc; + } + + return 0; + +error: + source_location_destroy(_src_loc); + bt_dwarf_die_destroy(die); + return -1; +} + +/** + * 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; +} + +BT_HIDDEN +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/plugins/lttng-utils/debug-info/bin-info.h b/plugins/lttng-utils/debug-info/bin-info.h new file mode 100644 index 00000000..2bcd9fae --- /dev/null +++ b/plugins/lttng-utils/debug-info/bin-info.h @@ -0,0 +1,236 @@ +#ifndef _BABELTRACE_BIN_INFO_H +#define _BABELTRACE_BIN_INFO_H + +/* + * Babeltrace - Executable and Shared Object Debug Info Reader + * + * Copyright 2015 Antoine Busque + * + * Author: Antoine Busque + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#define DEFAULT_DEBUG_DIR "/usr/lib/debug" +#define DEBUG_SUBDIR ".debug/" +#define BUILD_ID_SUBDIR ".build-id/" +#define BUILD_ID_SUFFIX ".debug" + +struct bin_info { + /* 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; + /* FDs to ELF and DWARF files. */ + int elf_fd; + int dwarf_fd; + /* 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; +}; + +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 + */ +BT_HIDDEN +int bin_info_init(void); + +/** + * 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. + */ +BT_HIDDEN +struct bin_info *bin_info_create(const char *path, uint64_t low_addr, + uint64_t memsz, bool is_pic, const char *debug_info_dir, + const char *target_prefix); + +/** + * Destroy the given bin_info instance + * + * @param bin bin_info instance to destroy + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +void source_location_destroy(struct source_location *src_loc); + +#endif /* _BABELTRACE_BIN_INFO_H */ diff --git a/plugins/lttng-utils/debug-info/crc32.c b/plugins/lttng-utils/debug-info/crc32.c new file mode 100644 index 00000000..e68c0434 --- /dev/null +++ b/plugins/lttng-utils/debug-info/crc32.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "crc32.h" + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +/* generated using the AUTODIN II polynomial + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + */ +static const uint32_t crctab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +int crc32(int fd, uint32_t *crc) +{ + int nr; + uint32_t _crc = ~0; + char buf[BUFSIZ], *p; + + if (fd < 0 || !crc) { + goto error; + } + + while ((nr = read(fd, buf, sizeof(buf))) > 0) { + for (p = buf; nr--; ++p) { + CRC(_crc, *p); + } + } + + if (nr < 0) { + goto error; + } + + *crc = ~_crc; + return 0; + +error: + return -1; +} diff --git a/plugins/lttng-utils/debug-info/crc32.h b/plugins/lttng-utils/debug-info/crc32.h new file mode 100644 index 00000000..4a229d63 --- /dev/null +++ b/plugins/lttng-utils/debug-info/crc32.h @@ -0,0 +1,55 @@ +#ifndef _BABELTRACE_CRC32_H +#define _BABELTRACE_CRC32_H + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/** + * Compute a 32-bit cyclic redundancy checksum for a given file. + * + * On success, the out parameter crc is set with the computed checksum + * value, + * + * @param fd File descriptor for the file for which to compute the CRC + * @param crc Out parameter, the computed checksum + * @returns 0 on success, -1 on failure. + */ +BT_HIDDEN +int crc32(int fd, uint32_t *crc); + +#endif /* _BABELTRACE_CRC32_H */ diff --git a/plugins/lttng-utils/debug-info/debug-info.c b/plugins/lttng-utils/debug-info/debug-info.c new file mode 100644 index 00000000..d84bf397 --- /dev/null +++ b/plugins/lttng-utils/debug-info/debug-info.c @@ -0,0 +1,2055 @@ +/* + * Babeltrace - Debug Information State Tracker + * + * 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 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT" +#include "logging.h" + +#include +#include + +#include +#include + +#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" + +#define DEFAULT_DEBUG_INFO_FIELD_NAME "debug_info" +#define LTTNG_UST_STATEDUMP_PREFIX "lttng_ust" +#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" + +struct debug_info_component { + gchar *arg_debug_dir; + gchar *arg_debug_info_field_name; + gchar *arg_target_prefix; + bt_bool arg_full_path; +}; + +struct debug_info_msg_iter { + struct debug_info_component *debug_info_component; + bt_self_message_iterator *input_iterator; + bt_self_component *self_comp; + bt_self_component_port_input_message_iterator *msg_iter; + + struct trace_ir_maps *ir_maps; + /* in_trace -> debug_info_mapping. */ + GHashTable *debug_info_map; +}; + +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 { + struct debug_info_component *comp; + const bt_trace *input_trace; + uint64_t 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; +}; + +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(); +} + +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) +{ + int ret; + struct debug_info_source *debug_info_src = NULL; + struct source_location *src_loc = NULL; + + 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_LOGD("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_LOGD("Error occured 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(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_signed_integer_get_value( + event_borrow_common_context_field(event, field_name)); +} + +static inline +int 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); + 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); + + return 0; +} + +static inline +int 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; + int ret; + + ret = 0; + + 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); + 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_unsigned_integer_get_value(curr_field); + } + + return ret; +} + +static +void event_get_payload_unsigned_integer_field_value(const bt_event *event, + const char *field_name, uint64_t *value) +{ + *value = bt_field_unsigned_integer_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) != NULL; +} + +static +struct debug_info_source *proc_debug_info_sources_get_entry( + 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); + 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; +} + +BT_HIDDEN +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(proc_dbg_info_src, ip); + +end: + return dbg_info_src; +} + +BT_HIDDEN +struct debug_info *debug_info_create(struct debug_info_component *comp, + const bt_trace *trace) +{ + int ret; + struct debug_info *debug_info; + + debug_info = g_new0(struct debug_info, 1); + if (!debug_info) { + goto end; + } + + 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; + +end: + return debug_info; +error: + g_free(debug_info); + return NULL; +} + +BT_HIDDEN +void debug_info_destroy(struct debug_info *debug_info) +{ + bt_trace_status status; + if (!debug_info) { + goto end; + } + + if (debug_info->vpid_to_proc_dbg_info_src) { + g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src); + } + + status = bt_trace_remove_destruction_listener(debug_info->input_trace, + debug_info->destruction_listener_id); + if (status != BT_TRACE_STATUS_OK) { + BT_LOGD("Trace destruction listener removal failed."); + } + + 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; + } + ret = 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; + } + + ret = event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME, + build_id); + if (ret) { + goto end; + } + + 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(path, baddr, memsz, is_pic, + debug_info->comp->arg_debug_dir, + debug_info->comp->arg_target_prefix); + 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; +} + +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) { + debug_info = debug_info_create(debug_it->debug_info_component, + trace); + g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace, + debug_info); + bt_trace_add_destruction_listener(trace, + trace_debug_info_remove_func, debug_it, + &debug_info->destruction_listener_id); + } + + 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_field_status status; + + BT_ASSERT(bt_field_get_class_type(curr_field) == + BT_FIELD_CLASS_TYPE_STRING); + + if (dbg_info_src) { + if (full_path) { + status = bt_field_string_set_value(curr_field, + dbg_info_src->bin_path); + } else { + status = bt_field_string_set_value(curr_field, + dbg_info_src->short_bin_path); + } + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set path component of \"bin\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + + status = bt_field_string_append(curr_field, ":"); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set colon component of \"bin\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + + status = bt_field_string_append(curr_field, dbg_info_src->bin_loc); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set bin location component of \"bin\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + } else { + status = bt_field_string_set_value(curr_field, ""); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set \"bin\" curr_field field's value: " + "str-fc-addr=%p", curr_field); + } + } +} + +static +void fill_debug_info_func_field(struct debug_info_source *dbg_info_src, + bt_field *curr_field) +{ + bt_field_status status; + + BT_ASSERT(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_STATUS_OK) { + BT_LOGE("Cannot set \"func\" curr_field field's value: " + "str-fc-addr=%p", curr_field); + } +} + +static +void fill_debug_info_src_field(struct debug_info_source *dbg_info_src, + bool full_path, bt_field *curr_field) +{ + bt_field_status status; + + BT_ASSERT(bt_field_get_class_type(curr_field) == + BT_FIELD_CLASS_TYPE_STRING); + + if (dbg_info_src && dbg_info_src->src_path) { + if (full_path) { + status = bt_field_string_set_value(curr_field, + dbg_info_src->src_path); + } else { + status = bt_field_string_set_value(curr_field, + dbg_info_src->short_src_path); + } + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set path component of \"src\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + + status = bt_field_string_append(curr_field, ":"); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set colon component of \"src\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + + status = bt_field_string_append(curr_field, dbg_info_src->line_no); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set line number component of \"src\" " + "curr_field field's value: str-fc-addr=%p", + curr_field); + } + } else { + status = bt_field_string_set_value(curr_field, ""); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set \"src\" curr_field field's value: " + "str-fc-addr=%p", curr_field); + } + } +} + +void fill_debug_info_field_empty(bt_field *debug_info_field) +{ + bt_field_status status; + bt_field *bin_field, *func_field, *src_field; + + BT_ASSERT(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(bt_field_get_class_type(bin_field) == + BT_FIELD_CLASS_TYPE_STRING); + BT_ASSERT(bt_field_get_class_type(func_field) == + BT_FIELD_CLASS_TYPE_STRING); + BT_ASSERT(bt_field_get_class_type(src_field) == + BT_FIELD_CLASS_TYPE_STRING); + + status = bt_field_string_set_value(bin_field, ""); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set \"bin\" bin_field field's value: " + "str-fc-addr=%p", bin_field); + } + + status = bt_field_string_set_value(func_field, ""); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set \"func\" func_field field's value: " + "str-fc-addr=%p", func_field); + } + + status = bt_field_string_set_value(src_field, ""); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set \"src\" src_field field's value: " + "str-fc-addr=%p", src_field); + } +} +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(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(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")); + fill_debug_info_func_field(dbg_info_src, + bt_field_structure_borrow_member_field_by_name( + debug_info_field, "func")); + 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")); +} + +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; + + 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_signed_integer_get_value(vpid_field); + ip = bt_field_unsigned_integer_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_LOGD("No debug information for this trace. Setting debug " + "info fields to empty strings."); + fill_debug_info_field_empty(out_debug_info_field); + } +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; + bt_clock_snapshot_state cs_state; + bt_event_class *out_event_class; + bt_packet *out_packet; + bt_event *out_event; + + 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(out_event_class); + + /* Borrow the input and output packets. */ + in_packet = bt_event_borrow_packet_const(in_event); + 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_state = + bt_message_event_borrow_default_clock_snapshot_const( + in_message, &cs); + + /* Create an output event message. */ + BT_ASSERT (cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); + out_message = bt_message_event_create_with_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(debug_it->input_iterator, + out_event_class, out_packet); + } + + if (!out_message) { + BT_LOGE("Error creating output event message."); + goto error; + } + + out_event = bt_message_event_borrow_event(out_message); + + /* Copy the original fields to the output event. */ + copy_event_content(in_event, out_event); + + /* + * 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); + +error: + 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; + + 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_LOGE("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; + + 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_LOGE("Error creating output stream end message: out-s-addr=%p", + out_stream); + } + + /* Remove stream from trace mapping hashtable. */ + trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream); + + return out_message; +} + +static +bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_clock_class *default_cc; + bt_clock_snapshot_state cs_state; + const bt_clock_snapshot *cs; + bt_message *out_message = NULL; + bt_packet *out_packet; + + 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); + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const( + bt_packet_borrow_stream_const(in_packet))); + if (default_cc) { + /* Borrow clock snapshot. */ + cs_state = + bt_message_packet_beginning_borrow_default_clock_snapshot_const( + in_message, &cs); + + /* Create an output packet beginning message. */ + BT_ASSERT(cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); + 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_LOGE("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) +{ + const bt_clock_snapshot *cs; + const bt_packet *in_packet; + const bt_clock_class *default_cc; + bt_clock_snapshot_state cs_state; + bt_message *out_message = NULL; + bt_packet *out_packet; + + 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); + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const( + bt_packet_borrow_stream_const(in_packet))); + if (default_cc) { + /* Borrow clock snapshot. */ + cs_state = + bt_message_packet_end_borrow_default_clock_snapshot_const( + in_message, &cs); + + /* Create an outpute packet end message. */ + BT_ASSERT(cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); + 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_LOGE("Error creating output packet end message: " + "out-p-addr=%p", out_packet); + } + + /* Remove packet from data mapping hashtable. */ + trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet); + + return out_message; +} + +static +bt_message *handle_msg_iterator_inactivity(struct debug_info_msg_iter *debug_it, + 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_stream_act_begin_message(struct debug_info_msg_iter *debug_it, + const bt_message *in_message) +{ + const bt_clock_snapshot *cs; + const bt_clock_class *default_cc; + bt_message *out_message = NULL; + bt_stream *out_stream; + uint64_t cs_value; + bt_message_stream_activity_clock_snapshot_state cs_state; + + const bt_stream *in_stream = + bt_message_stream_activity_beginning_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); + + out_message = bt_message_stream_activity_beginning_create( + debug_it->input_iterator, out_stream); + if (!out_message) { + BT_LOGE("Error creating output stream activity beginning " + "message: out-s-addr=%p", out_stream); + goto error; + } + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const(in_stream)); + if (default_cc) { + /* Borrow clock snapshot. */ + cs_state = + bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const( + in_message, &cs); + + if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) { + cs_value = bt_clock_snapshot_get_value(cs); + bt_message_stream_activity_beginning_set_default_clock_snapshot( + out_message, cs_value); + } else { + bt_message_stream_activity_beginning_set_default_clock_snapshot_state( + out_message, cs_state); + } + } + +error: + return out_message; +} + +static +bt_message *handle_stream_act_end_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_stream *in_stream; + bt_message *out_message; + bt_stream *out_stream; + uint64_t cs_value; + bt_message_stream_activity_clock_snapshot_state cs_state; + + in_stream = bt_message_stream_activity_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); + + out_message = bt_message_stream_activity_end_create( + debug_it->input_iterator, out_stream); + if (!out_message) { + BT_LOGE("Error creating output stream activity end message: " + "out-s-addr=%p", out_stream); + goto error; + } + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const(in_stream)); + + if (default_cc) { + cs_state = + bt_message_stream_activity_end_borrow_default_clock_snapshot_const( + in_message, &cs); + + if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN ) { + cs_value = bt_clock_snapshot_get_value(cs); + bt_message_stream_activity_end_set_default_clock_snapshot( + out_message, cs_value); + } else { + bt_message_stream_activity_end_set_default_clock_snapshot_state( + out_message, cs_state); + } + } + +error: + return out_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; + const bt_clock_class *default_cc; + uint64_t discarded_events, begin_cs_value, end_cs_value; + bt_clock_snapshot_state begin_cs_state, end_cs_state; + bt_property_availability prop_avail; + bt_message *out_message = NULL; + bt_stream *out_stream; + + 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); + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const(in_stream)); + if (default_cc) { + begin_cs_state = + bt_message_discarded_events_borrow_default_beginning_clock_snapshot_const( + in_message, &begin_cs); + end_cs_state = + bt_message_discarded_events_borrow_default_end_clock_snapshot_const( + in_message, &end_cs); + /* + * Both clock snapshots should be known as we check that the + * all input stream classes have an always known clock. Unknown + * clock is not yet supported. + */ + BT_ASSERT(begin_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN && + end_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); + + 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_LOGE("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; + const bt_clock_class *default_cc; + const bt_stream *in_stream; + uint64_t discarded_packets, begin_cs_value, end_cs_value; + bt_clock_snapshot_state begin_cs_state, end_cs_state; + bt_property_availability prop_avail; + bt_message *out_message = NULL; + bt_stream *out_stream; + + 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); + + default_cc = bt_stream_class_borrow_default_clock_class_const( + bt_stream_borrow_class_const(in_stream)); + if (default_cc) { + begin_cs_state = + bt_message_discarded_packets_borrow_default_beginning_clock_snapshot_const( + in_message, &begin_cs); + + end_cs_state = + bt_message_discarded_packets_borrow_default_end_clock_snapshot_const( + in_message, &end_cs); + + /* + * Both clock snapshots should be known as we check that the + * all input stream classes have an always known clock. Unknown + * clock is not yet supported. + */ + BT_ASSERT(begin_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN && + end_cs_state == BT_CLOCK_SNAPSHOT_STATE_KNOWN); + + 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_LOGE("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(debug_it, + in_message); + break; + case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING: + out_message = handle_stream_act_begin_message(debug_it, + in_message); + break; + case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END: + out_message = handle_stream_act_end_message(debug_it, + 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: + abort(); + break; + } + + return out_message; +} + +static +int init_from_params(struct debug_info_component *debug_info_component, + const bt_value *params) +{ + const bt_value *value = NULL; + int ret = 0; + + 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; + } + + return ret; +} + +BT_HIDDEN +bt_self_component_status debug_info_comp_init( + bt_self_component_filter *self_comp, + const bt_value *params, UNUSED_VAR void *init_method_data) +{ + int ret; + struct debug_info_component *debug_info_comp; + bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK; + + BT_LOGD("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_LOGE_STR("Failed to allocate one debug_info component."); + goto error; + } + + bt_self_component_set_data( + bt_self_component_filter_as_self_component(self_comp), + debug_info_comp); + + status = bt_self_component_filter_add_input_port(self_comp, "in", + NULL, NULL); + if (status != BT_SELF_COMPONENT_STATUS_OK) { + goto error; + } + + status = bt_self_component_filter_add_output_port(self_comp, "out", + NULL, NULL); + if (status != BT_SELF_COMPONENT_STATUS_OK) { + goto error; + } + + ret = init_from_params(debug_info_comp, params); + if (ret) { + BT_LOGE("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( + bt_self_component_filter_as_self_component(self_comp), + NULL); + + if (status == BT_SELF_COMPONENT_STATUS_OK) { + status = BT_SELF_COMPONENT_STATUS_ERROR; + } +end: + return status; +} + +BT_HIDDEN +void debug_info_comp_finalize(bt_self_component_filter *self_comp) +{ + struct debug_info_component *debug_info = + bt_self_component_get_data( + bt_self_component_filter_as_self_component( + self_comp)); + BT_LOGD("Finalizing debug_info self_component: comp-addr=%p", + self_comp); + + destroy_debug_info_comp(debug_info); +} + +BT_HIDDEN +bt_self_message_iterator_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_self_component_port_input_message_iterator *upstream_iterator = NULL; + bt_message_iterator_status upstream_iterator_ret_status; + struct debug_info_msg_iter *debug_info_msg_iter; + struct debug_info_component *debug_info = NULL; + bt_self_message_iterator_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_SELF_MESSAGE_ITERATOR_STATUS_OK; + + self_comp = bt_self_message_iterator_borrow_component(self_msg_iter); + BT_ASSERT(self_comp); + + debug_info = bt_self_component_get_data(self_comp); + BT_ASSERT(debug_info); + + debug_info_msg_iter = bt_self_message_iterator_get_data(self_msg_iter); + BT_ASSERT(debug_info_msg_iter); + + upstream_iterator = debug_info_msg_iter->msg_iter; + BT_ASSERT(upstream_iterator); + + upstream_iterator_ret_status = + bt_self_component_port_input_message_iterator_next( + upstream_iterator, &input_msgs, count); + if (upstream_iterator_ret_status != BT_MESSAGE_ITERATOR_STATUS_OK) { + /* + * No messages were returned. Not necessarily an error. Convert + * the upstream message iterator status to a self status. + */ + status = bt_common_message_iterator_status_to_self( + upstream_iterator_ret_status); + goto end; + } + + /* + * There should never be more received messages than the capacity we + * provided. + */ + BT_ASSERT(*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]); + } + + status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; +end: + return status; +} + +BT_HIDDEN +bt_self_message_iterator_status debug_info_msg_iter_init( + bt_self_message_iterator *self_msg_iter, + bt_self_component_filter *self_comp, + bt_self_component_port_output *self_port) +{ + bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK; + struct bt_self_component_port_input *input_port; + bt_self_component_port_input_message_iterator *upstream_iterator; + struct debug_info_msg_iter *debug_info_msg_iter; + gchar *debug_info_field_name; + + /* Borrow the upstream input port. */ + input_port = bt_self_component_filter_borrow_input_port_by_name( + self_comp, "in"); + if (!input_port) { + status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR; + goto end; + } + + /* Create an iterator on the upstream component. */ + upstream_iterator = bt_self_component_port_input_message_iterator_create( + input_port); + if (!upstream_iterator) { + status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; + goto end; + } + + debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1); + if (!debug_info_msg_iter) { + status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; + goto end; + } + + /* Create hashtable to 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) { + g_free(debug_info_msg_iter); + status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; + goto end; + } + + debug_info_msg_iter->self_comp = + bt_self_component_filter_as_self_component(self_comp); + + BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF( + debug_info_msg_iter->msg_iter, upstream_iterator); + + debug_info_msg_iter->debug_info_component = bt_self_component_get_data( + bt_self_component_filter_as_self_component( + self_comp)); + + 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( + bt_self_component_filter_as_self_component(self_comp), + debug_info_field_name); + if (!debug_info_msg_iter->ir_maps) { + g_hash_table_destroy(debug_info_msg_iter->debug_info_map); + g_free(debug_info_msg_iter); + status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM; + goto end; + } + + bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter); + + debug_info_msg_iter->input_iterator = self_msg_iter; + +end: + return status; +} + +BT_HIDDEN +bt_bool debug_info_msg_iter_can_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_ASSERT(debug_info_msg_iter); + + return bt_self_component_port_input_message_iterator_can_seek_beginning( + debug_info_msg_iter->msg_iter); +} + +BT_HIDDEN +bt_self_message_iterator_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_status status = BT_MESSAGE_ITERATOR_STATUS_OK; + + BT_ASSERT(debug_info_msg_iter); + + /* Ask the upstream component to seek to the beginning. */ + status = bt_self_component_port_input_message_iterator_seek_beginning( + debug_info_msg_iter->msg_iter); + if (status != BT_MESSAGE_ITERATOR_STATUS_OK) { + 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 bt_common_message_iterator_status_to_self(status); +} + +BT_HIDDEN +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); + + bt_self_component_port_input_message_iterator_put_ref( + debug_info_msg_iter->msg_iter); + + trace_ir_maps_destroy(debug_info_msg_iter->ir_maps); + g_hash_table_destroy(debug_info_msg_iter->debug_info_map); + + g_free(debug_info_msg_iter); +} diff --git a/plugins/lttng-utils/debug-info/debug-info.h b/plugins/lttng-utils/debug-info/debug-info.h new file mode 100644 index 00000000..bfdbccc1 --- /dev/null +++ b/plugins/lttng-utils/debug-info/debug-info.h @@ -0,0 +1,68 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_H + +/* + * Babeltrace - Debug information Plugin + * + * Copyright (c) 2015-2019 EfficiOS Inc. + * Copyright (c) 2015 Antoine Busque + * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#define VPID_FIELD_NAME "vpid" +#define IP_FIELD_NAME "ip" + +BT_HIDDEN +bt_self_component_status debug_info_comp_init( + bt_self_component_filter *self_comp, + const bt_value *params, void *init_method_data); + +BT_HIDDEN +void debug_info_comp_finalize(bt_self_component_filter *self_comp); + +BT_HIDDEN +bt_self_message_iterator_status debug_info_msg_iter_init( + bt_self_message_iterator *self_msg_iter, + bt_self_component_filter *self_comp, + bt_self_component_port_output *self_port); + +BT_HIDDEN +bt_self_message_iterator_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_HIDDEN +bt_bool debug_info_msg_iter_can_seek_beginning( + bt_self_message_iterator *message_iterator); + +BT_HIDDEN +bt_self_message_iterator_status debug_info_msg_iter_seek_beginning( + bt_self_message_iterator *message_iterator); + +BT_HIDDEN +void debug_info_msg_iter_finalize(bt_self_message_iterator *it); + +#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */ diff --git a/plugins/lttng-utils/debug-info/dwarf.c b/plugins/lttng-utils/debug-info/dwarf.c new file mode 100644 index 00000000..534d2883 --- /dev/null +++ b/plugins/lttng-utils/debug-info/dwarf.c @@ -0,0 +1,375 @@ +/* + * dwarf.c + * + * Babeltrace - DWARF Information Reader + * + * Copyright 2015 Antoine Busque + * + * Author: Antoine Busque + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "dwarf.h" + +BT_HIDDEN +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; +} + +BT_HIDDEN +void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu) +{ + g_free(cu); +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +void bt_dwarf_die_destroy(struct bt_dwarf_die *die) +{ + if (!die) { + return; + } + + g_free(die->dwarf_die); + g_free(die); +} + +BT_HIDDEN +int bt_dwarf_die_has_children(struct bt_dwarf_die *die) +{ + return dwarf_haschildren(die->dwarf_die); +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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; +} + +BT_HIDDEN +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/plugins/lttng-utils/debug-info/dwarf.h b/plugins/lttng-utils/debug-info/dwarf.h new file mode 100644 index 00000000..707431f9 --- /dev/null +++ b/plugins/lttng-utils/debug-info/dwarf.h @@ -0,0 +1,235 @@ +#ifndef _BABELTRACE_DWARF_H +#define _BABELTRACE_DWARF_H + +/* + * Babeltrace - DWARF Information Reader + * + * Copyright 2015 Antoine Busque + * + * Author: Antoine Busque + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +/* + * 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. + */ +BT_HIDDEN +struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info); + +/** + * Destroy the given bt_dwarf_cu instance. + * + * @param cu bt_dwarf_cu instance + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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. + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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. + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 + */ +BT_HIDDEN +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 succes, -1 on failure + */ +BT_HIDDEN +int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, + bool *contains); + +#endif /* _BABELTRACE_DWARF_H */ diff --git a/plugins/lttng-utils/debug-info/logging.c b/plugins/lttng-utils/debug-info/logging.c new file mode 100644 index 00000000..78c2e17f --- /dev/null +++ b/plugins/lttng-utils/debug-info/logging.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level +#include + +BT_LOG_INIT_LOG_LEVEL(bt_plugin_lttng_utils_debug_info_log_level, + "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL"); diff --git a/plugins/lttng-utils/debug-info/logging.h b/plugins/lttng-utils/debug-info/logging.h new file mode 100644 index 00000000..b77a02f9 --- /dev/null +++ b/plugins/lttng-utils/debug-info/logging.h @@ -0,0 +1,31 @@ +#ifndef PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H +#define PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H + +/* + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level +#include + +BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_lttng_utils_debug_info_log_level); + +#endif /* PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H */ diff --git a/plugins/lttng-utils/debug-info/trace-ir-data-copy.c b/plugins/lttng-utils/debug-info/trace-ir-data-copy.c new file mode 100644 index 00000000..78f611cb --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-data-copy.c @@ -0,0 +1,287 @@ +/* + * Babeltrace - Trace IR data object copy + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-DATA-COPY" +#include "logging.h" + +#include +#include + +#include + +#include "trace-ir-data-copy.h" + +BT_HIDDEN +void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace) +{ + bt_trace_status status; + const char *trace_name; + + BT_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) { + status = bt_trace_set_name(out_trace, trace_name); + if (status != BT_TRACE_STATUS_OK) { + BT_LOGE("Cannot set trace's name: trace-addr=%p, name=\"%s\"", + out_trace, trace_name); + goto end; + } + } + + BT_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p", + in_trace, out_trace); +end: + return; +} + +BT_HIDDEN +void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream) +{ + const char *stream_name; + bt_stream_status status; + + BT_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) { + status = bt_stream_set_name(out_stream, stream_name); + if (status != BT_STREAM_STATUS_OK) { + BT_LOGE("Cannot set stream's name: stream-addr=%p, " + "name=%s", out_stream, stream_name); + goto end; + } + } + + BT_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p", + in_stream, out_stream); +end: + return; +} + +BT_HIDDEN +void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet) +{ + const bt_field *in_context_field; + bt_field *out_context_field; + + BT_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); + copy_field_content(in_context_field, out_context_field); + } + + BT_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p", + in_packet, out_packet); + return; +} + +BT_HIDDEN +void copy_event_content(const bt_event *in_event, bt_event *out_event) +{ + 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_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(out_common_ctx_field); + copy_field_content(in_common_ctx_field, + out_common_ctx_field); + } + + 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(out_specific_ctx_field); + copy_field_content(in_specific_ctx_field, + out_specific_ctx_field); + } + + 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(out_payload_field); + copy_field_content(in_payload_field, + out_payload_field); + } + + BT_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p", + in_event, out_event); +} + +BT_HIDDEN +void copy_field_content(const bt_field *in_field, bt_field *out_field) +{ + 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(in_fc_type == out_fc_type); + + BT_LOGD("Copying content of field: in-f-addr=%p, out-f-addr=%p", + in_field, out_field); + switch (in_fc_type) { + case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: + case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: + bt_field_unsigned_integer_set_value(out_field, + bt_field_unsigned_integer_get_value(in_field)); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: + case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: + bt_field_signed_integer_set_value(out_field, + bt_field_signed_integer_get_value(in_field)); + break; + case BT_FIELD_CLASS_TYPE_REAL: + bt_field_real_set_value(out_field, + bt_field_real_get_value(in_field)); + break; + case BT_FIELD_CLASS_TYPE_STRING: + { + const char *str = bt_field_string_get_value(in_field); + bt_field_status status = bt_field_string_set_value(out_field, str); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set string field's value: " + "str-field-addr=%p, str=%s" PRId64, + out_field, str); + } + break; + } + case 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); + + copy_field_content(in_member_field, + out_member_field); + } + break; + } + case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: + /* fall through */ + case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: + { + const bt_field *in_element_field; + bt_field *out_element_field; + uint64_t i, array_len; + bt_field_status status; + + array_len = bt_field_array_get_length(in_field); + + if (in_fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY) { + status = bt_field_dynamic_array_set_length(out_field, + array_len); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot set dynamic array field's " + "length field: field-addr=%p, " + "length=%" PRIu64, out_field, array_len); + } + } + + 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); + copy_field_content(in_element_field, out_element_field); + } + break; + } + case BT_FIELD_CLASS_TYPE_VARIANT: + { + bt_field_status 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_field_index( + in_field); + status = bt_field_variant_select_option_field(out_field, + in_selected_option_idx); + if (status != BT_FIELD_STATUS_OK) { + BT_LOGE("Cannot select variant field's option field: " + "var-field-addr=%p, opt-index=%" PRId64, + out_field, in_selected_option_idx); + } + + 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); + + copy_field_content(in_option_field, out_option_field); + + break; + } + default: + abort(); + } + BT_LOGD("Copied content of field: in-f-addr=%p, out-f-addr=%p", + in_field, out_field); +} diff --git a/plugins/lttng-utils/debug-info/trace-ir-data-copy.h b/plugins/lttng-utils/debug-info/trace-ir-data-copy.h new file mode 100644 index 00000000..97eface5 --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-data-copy.h @@ -0,0 +1,44 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H + +/* + * Babeltrace - Trace IR data object copy + * + * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "trace-ir-mapping.h" + +BT_HIDDEN +void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace); +BT_HIDDEN +void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream); +BT_HIDDEN +void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet); +BT_HIDDEN +void copy_event_content(const bt_event *in_event, bt_event *out_event); +BT_HIDDEN +void copy_field_content(const bt_field *in_field, bt_field *out_field); + +#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H */ diff --git a/plugins/lttng-utils/debug-info/trace-ir-mapping.c b/plugins/lttng-utils/debug-info/trace-ir-mapping.c new file mode 100644 index 00000000..3ed687c6 --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-mapping.c @@ -0,0 +1,690 @@ +/* + * Babeltrace - Mapping of IR metadata and data object between input and output + * trace + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-MAPPING" +#include "logging.h" + +#include + +#include +#include +/* For bt_property_availability */ +#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) +{ + int ret; + bt_trace_class *out_trace_class; + + BT_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class); + + BT_ASSERT(ir_maps); + BT_ASSERT(in_trace_class); + + /* Create the ouput trace class. */ + out_trace_class = bt_trace_class_create(ir_maps->self_comp); + if (!out_trace_class) { + BT_LOGE_STR("Error create output trace class"); + goto end; + } + + /* If not, create a new one and add it to the mapping. */ + ret = copy_trace_class_content(in_trace_class, out_trace_class); + if (ret) { + BT_LOGE_STR("Error copy content to output trace class"); + out_trace_class = NULL; + goto end; + } + + BT_LOGD("Created new mapped trace class: in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, out_trace_class); + +end: + return out_trace_class; +} + +static +bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps, + const bt_trace *in_trace) +{ + bt_trace *out_trace; + const bt_trace_class *in_trace_class; + struct trace_ir_metadata_maps *metadata_maps; + + BT_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) { + metadata_maps->output_trace_class = + create_new_mapped_trace_class(ir_maps, in_trace_class); + if (!metadata_maps->output_trace_class) { + out_trace = NULL; + goto end; + } + } + + out_trace = bt_trace_create(metadata_maps->output_trace_class); + if (!out_trace) { + BT_LOGE_STR("Error create output trace"); + goto end; + } + + /* If not, create a new one and add it to the mapping. */ + copy_trace_content(in_trace, out_trace); + + BT_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p", + in_trace, out_trace); +end: + return out_trace; +} + +static +bt_stream_class *borrow_mapped_stream_class(struct trace_ir_metadata_maps *md_maps, + const bt_stream_class *in_stream_class) +{ + BT_ASSERT(md_maps); + BT_ASSERT(in_stream_class); + + return g_hash_table_lookup(md_maps->stream_class_map, + (gpointer) in_stream_class); +} + +static +bt_stream_class *create_new_mapped_stream_class(struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class) +{ + int ret; + bt_stream_class *out_stream_class; + struct trace_ir_metadata_maps *md_maps; + + BT_LOGD("Creating new mapped stream class: in-sc-addr=%p", + in_stream_class); + + md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, + in_stream_class); + + BT_ASSERT(md_maps); + BT_ASSERT(in_stream_class); + BT_ASSERT(!borrow_mapped_stream_class(md_maps, in_stream_class)); + + /* Create an out_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_LOGE_STR("Error create output stream class"); + goto end; + } + + /* If not, create a new one and add it to the mapping. */ + ret = copy_stream_class_content(ir_maps, in_stream_class, + out_stream_class); + if (ret) { + BT_LOGE_STR("Error copy content to output stream class"); + out_stream_class = NULL; + goto end; + } + + g_hash_table_insert(md_maps->stream_class_map, + (gpointer) in_stream_class, out_stream_class); + + BT_LOGD("Created new mapped stream class: in-sc-addr=%p, out-sc-addr=%p", + in_stream_class, out_stream_class); + +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(d_maps); + BT_ASSERT(in_stream); + + return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream); +} + +BT_HIDDEN +bt_stream *trace_ir_mapping_create_new_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream) +{ + struct trace_ir_data_maps *d_maps; + struct trace_ir_metadata_maps *md_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_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream); + + BT_ASSERT(ir_maps); + BT_ASSERT(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) { + d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace); + if (!d_maps->output_trace) { + goto end; + } + } + + 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); + if (bt_stream_class_default_clock_is_always_known(in_stream_class) + == BT_FALSE) { + BT_LOGE("Stream class default clock class is not always " + "known: in-sc-addr=%p", in_stream_class); + goto end; + } + + md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class); + out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class); + if (!out_stream_class) { + out_stream_class = create_new_mapped_stream_class(ir_maps, + in_stream_class); + if (!out_stream_class) { + goto end; + } + } + BT_ASSERT(out_stream_class); + + out_stream = bt_stream_create_with_id(out_stream_class, + d_maps->output_trace, bt_stream_get_id(in_stream)); + if (!out_stream) { + BT_LOGE_STR("Error creating output stream"); + goto end; + } + /* + * Release our ref since the trace object will be managing the life + * time of the stream objects. + */ + + copy_stream_content(in_stream, out_stream); + + g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream, + out_stream); + + BT_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p", + in_stream, out_stream); + +end: + return out_stream; +} + +BT_HIDDEN +bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps, + const bt_stream *in_stream) +{ + BT_ASSERT(ir_maps); + BT_ASSERT(in_stream); + struct trace_ir_data_maps *d_maps; + + 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_HIDDEN +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 *out_event_class; + const bt_trace_class *in_trace_class; + const bt_stream_class *in_stream_class; + bt_stream_class *out_stream_class; + struct trace_ir_metadata_maps *md_maps; + int ret; + + BT_LOGD("Creating new mapped event class: in-ec-addr=%p", + in_event_class); + + BT_ASSERT(ir_maps); + BT_ASSERT(in_event_class); + + in_trace_class = bt_stream_class_borrow_trace_class_const( + bt_event_class_borrow_stream_class_const( + in_event_class)); + + md_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, in_trace_class); + + BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class)); + + in_stream_class = + bt_event_class_borrow_stream_class_const(in_event_class); + BT_ASSERT(in_stream_class); + + /* Get the right output stream class to add the new event class to. */ + out_stream_class = borrow_mapped_stream_class(md_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_LOGE_STR("Error creating output event class"); + goto end; + } + + /* If not, create a new one and add it to the mapping. */ + ret = copy_event_class_content(ir_maps, in_event_class, + out_event_class); + if (ret) { + BT_LOGE_STR("Error copy content to output event class"); + out_event_class = NULL; + goto end; + } + + g_hash_table_insert(md_maps->event_class_map, + (gpointer) in_event_class, out_event_class); + + BT_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p", + in_event_class, out_event_class); + +end: + return out_event_class; +} + +BT_HIDDEN +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(ir_maps); + BT_ASSERT(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(d_maps); + BT_ASSERT(in_packet); + + return g_hash_table_lookup(d_maps->packet_map, + (gpointer) in_packet); +} + +BT_HIDDEN +bt_packet *trace_ir_mapping_create_new_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet) +{ + struct trace_ir_data_maps *d_maps; + const bt_trace *in_trace; + const bt_stream *in_stream; + bt_packet *out_packet; + bt_stream *out_stream; + + BT_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. */ + 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_LOGE_STR("Error create output packet"); + goto end; + } + + /* + * Release our ref since the stream object will be managing the life + * time of the packet objects. + */ + copy_packet_content(in_packet, out_packet); + + g_hash_table_insert(d_maps->packet_map, + (gpointer) in_packet, out_packet); + + BT_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p", + in_packet, out_packet); + +end: + return out_packet; +} + +BT_HIDDEN +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(ir_maps); + BT_ASSERT(in_packet); + + d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); + + return borrow_mapped_packet(d_maps, in_packet); +} + +BT_HIDDEN +void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps, + const bt_packet *in_packet) +{ + gboolean ret; + + struct trace_ir_data_maps *d_maps; + 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); +} + +BT_HIDDEN +void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps, + const bt_stream *in_stream) +{ + gboolean ret; + struct trace_ir_data_maps *d_maps; + + 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) +{ + struct trace_ir_data_maps *d_maps = + g_new0(struct trace_ir_data_maps, 1); + if (!d_maps) { + BT_LOGE_STR("Error allocating trace_ir_maps"); + goto error; + } + + 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); + + bt_trace_add_destruction_listener(in_trace, trace_ir_data_maps_remove_func, + ir_maps, &d_maps->destruction_listener_id); +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) +{ + struct trace_ir_metadata_maps *md_maps = + g_new0(struct trace_ir_metadata_maps, 1); + if (!md_maps) { + BT_LOGE_STR("Error allocating trace_ir_maps"); + goto error; + } + + 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_LOGE_STR("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); + + bt_trace_class_add_destruction_listener(in_trace_class, + trace_ir_metadata_maps_remove_func, + ir_maps, &md_maps->destruction_listener_id); +error: + return md_maps; +} + +BT_HIDDEN +void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps) +{ + bt_trace_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_STATUS_OK) { + BT_LOGD("Trace destruction listener removal failed."); + } + + g_free(maps); +} + +BT_HIDDEN +void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps) +{ + bt_trace_class_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); + } + + if (maps->fc_resolving_ctx) { + 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_STATUS_OK) { + BT_LOGD("Trace destruction listener removal failed."); + } + + 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); + } +} + +BT_HIDDEN +void trace_ir_maps_destroy(struct trace_ir_maps *maps) +{ + if (!maps) { + return; + } + + if (maps->debug_info_field_class_name) { + 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); +} + +BT_HIDDEN +struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, + const char *debug_info_field_name) +{ + struct trace_ir_maps *trace_ir_maps = + g_new0(struct trace_ir_maps, 1); + if (!trace_ir_maps) { + BT_LOGE_STR("Error allocating trace_ir_maps"); + goto error; + } + + /* Copy debug info field name received from the user. */ + trace_ir_maps->debug_info_field_class_name = + g_strdup(debug_info_field_name); + if (!trace_ir_maps->debug_info_field_class_name) { + BT_LOGE_STR("Cannot copy debug info field name"); + goto error; + } + + trace_ir_maps->self_comp = self_comp; + + trace_ir_maps->data_maps = g_hash_table_new_full(g_direct_hash, + g_direct_equal, (GDestroyNotify) NULL, + (GDestroyNotify) trace_ir_data_maps_destroy); + + trace_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(trace_ir_maps); + trace_ir_maps = NULL; +end: + return trace_ir_maps; +} diff --git a/plugins/lttng-utils/debug-info/trace-ir-mapping.h b/plugins/lttng-utils/debug-info/trace-ir-mapping.h new file mode 100644 index 00000000..3601e81e --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-mapping.h @@ -0,0 +1,274 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H +/* + * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include +#include + +#include "debug-info.h" + +/* 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 { + 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; + + uint64_t destruction_listener_id; +}; + +struct trace_ir_data_maps { + 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; + + uint64_t destruction_listener_id; +}; + +struct trace_ir_maps { + /* + * 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; +}; + +BT_HIDDEN +struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, + const char *debug_info_field_name); + +BT_HIDDEN +void trace_ir_maps_clear(struct trace_ir_maps *maps); + +BT_HIDDEN +void trace_ir_maps_destroy(struct trace_ir_maps *maps); + +BT_HIDDEN +struct trace_ir_data_maps *trace_ir_data_maps_create( + struct trace_ir_maps *ir_maps, + const bt_trace *in_trace); + +BT_HIDDEN +void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps); + +BT_HIDDEN +struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( + struct trace_ir_maps *ir_maps, + const bt_trace_class *in_trace_class); + +BT_HIDDEN +void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps); + +BT_HIDDEN +bt_stream *trace_ir_mapping_create_new_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +BT_HIDDEN +bt_stream *trace_ir_mapping_borrow_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +BT_HIDDEN +void trace_ir_mapping_remove_mapped_stream( + struct trace_ir_maps *ir_maps, + const bt_stream *in_stream); + +BT_HIDDEN +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_HIDDEN +bt_event_class *trace_ir_mapping_borrow_mapped_event_class( + struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class); + +BT_HIDDEN +bt_packet *trace_ir_mapping_create_new_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet); + +BT_HIDDEN +bt_packet *trace_ir_mapping_borrow_mapped_packet( + struct trace_ir_maps *ir_maps, + const bt_packet *in_packet); + +BT_HIDDEN +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_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H */ diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c new file mode 100644 index 00000000..5655e62d --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c @@ -0,0 +1,615 @@ +/* + * Babeltrace - Trace IR metadata object copy + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-COPY" +#include "logging.h" + +#include +#include + +#include + +#include "trace-ir-metadata-copy.h" +#include "trace-ir-metadata-field-class-copy.h" +#include "utils.h" + +BT_HIDDEN +int copy_trace_class_content(const bt_trace_class *in_trace_class, + bt_trace_class *out_trace_class) +{ + int ret = 0; + uint64_t i, env_field_count; + const char *in_trace_class_name; + bt_uuid in_uuid; + + BT_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, out_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); + + in_trace_class_name = bt_trace_class_get_name(in_trace_class); + if (in_trace_class_name) { + bt_trace_class_set_name(out_trace_class, in_trace_class_name); + } + + in_uuid = bt_trace_class_get_uuid(in_trace_class); + if (in_uuid) { + bt_trace_class_set_uuid(out_trace_class, in_uuid); + } + + /* + * Go over all the entries in the environment section of the trace class + * and copy the content to the new trace class. + */ + env_field_count = bt_trace_class_get_environment_entry_count(in_trace_class); + for (i = 0; i < env_field_count; i++) { + const char *value_name; + const bt_value *value = NULL; + bt_trace_class_status trace_class_status; + + bt_trace_class_borrow_environment_entry_by_index_const( + in_trace_class, i, &value_name, &value); + + BT_LOGD("Copying trace class environnement entry: " + "index=%" PRId64 ", value-addr=%p, value-name=%s", + i, value, value_name); + + BT_ASSERT(value_name); + BT_ASSERT(value); + + if (bt_value_is_integer(value)) { + trace_class_status = + bt_trace_class_set_environment_entry_integer( + out_trace_class, value_name, + bt_value_integer_get(value)); + } else if (bt_value_is_string(value)) { + trace_class_status = + bt_trace_class_set_environment_entry_string( + out_trace_class, value_name, + bt_value_string_get(value)); + } else { + abort(); + } + + if (trace_class_status != BT_TRACE_CLASS_STATUS_OK) { + ret = -1; + goto error; + } + } + + BT_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p", + in_trace_class, out_trace_class); +error: + return ret; +} + +static +int copy_clock_class_content(const bt_clock_class *in_clock_class, + bt_clock_class *out_clock_class) +{ + bt_clock_class_status status; + const char *clock_class_name, *clock_class_description; + int64_t seconds; + uint64_t cycles; + bt_uuid in_uuid; + int ret = 0; + + BT_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) { + status = bt_clock_class_set_name(out_clock_class, clock_class_name); + if (status != BT_CLOCK_CLASS_STATUS_OK) { + BT_LOGE("Error setting clock class' name cc-addr=%p, name=%p", + out_clock_class, clock_class_name); + out_clock_class = NULL; + ret = -1; + goto error; + } + } + + clock_class_description = bt_clock_class_get_description(in_clock_class); + + if (clock_class_description) { + status = bt_clock_class_set_description(out_clock_class, + clock_class_description); + if (status != BT_CLOCK_CLASS_STATUS_OK) { + BT_LOGE("Error setting clock class' description cc-addr=%p, " + "name=%p", out_clock_class, clock_class_description); + out_clock_class = NULL; + ret = -1; + goto error; + } + } + + 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_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p", + in_clock_class, out_clock_class); + +error: + return ret; +} + +static +bt_clock_class *borrow_mapped_clock_class( + struct trace_ir_metadata_maps *md_maps, + const bt_clock_class *in_clock_class) +{ + BT_ASSERT(md_maps); + BT_ASSERT(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) +{ + bt_clock_class *out_clock_class; + int ret; + + BT_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_LOGE_STR("Cannot create clock class"); + goto end; + } + /* If not, create a new one and add it to the mapping. */ + ret = copy_clock_class_content(in_clock_class, out_clock_class); + if (ret) { + BT_LOGE_STR("Cannot copy clock class"); + goto end; + } + + g_hash_table_insert(md_maps->clock_class_map, + (gpointer) in_clock_class, out_clock_class); + + BT_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; +} + +BT_HIDDEN +int copy_stream_class_content(struct trace_ir_maps *ir_maps, + const bt_stream_class *in_stream_class, + bt_stream_class *out_stream_class) +{ + 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; + bt_stream_class_status status; + const char *in_name; + int ret = 0; + + BT_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) { + /* 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); + } + bt_stream_class_set_default_clock_class(out_stream_class, + out_clock_class); + + } + + in_name = bt_stream_class_get_name(in_stream_class); + if (in_name) { + status = bt_stream_class_set_name(out_stream_class, in_name); + if (status != BT_STREAM_CLASS_STATUS_OK) { + BT_LOGE("Error set stream class name: out-sc-addr=%p, " + "name=%s", out_stream_class, in_name); + ret = -1; + goto error; + } + } + + 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) { + /* Copy packet context. */ + out_packet_context_fc = create_field_class_copy( + md_maps, in_packet_context_fc); + + ret = copy_field_class_content(md_maps, + in_packet_context_fc, out_packet_context_fc); + if (ret) { + ret = -1; + goto error; + } + + status = bt_stream_class_set_packet_context_field_class( + out_stream_class, out_packet_context_fc); + if (status != BT_STREAM_CLASS_STATUS_OK) { + BT_LOGE("Error setting stream class' packet context " + "field class: sc-addr=%p, packet-fc-addr=%p", + out_stream_class, out_packet_context_fc); + ret = -1; + goto error; + } + } + + /* + * 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) { + /* 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); + + ret = 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 (ret) { + goto error; + } + + status = bt_stream_class_set_event_common_context_field_class( + out_stream_class, out_common_context_fc); + if (status != BT_STREAM_CLASS_STATUS_OK) { + BT_LOGE("Error setting stream class' packet context " + "field class: sc-addr=%p, packet-fc-addr=%p", + out_stream_class, out_common_context_fc); + ret = -1; + goto error; + } + } + + /* Set packet snapshot boolean fields. */ + BT_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p", + in_stream_class, out_stream_class); +error: + return ret; +} + +BT_HIDDEN +int copy_event_class_content(struct trace_ir_maps *ir_maps, + const bt_event_class *in_event_class, + bt_event_class *out_event_class) +{ + 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 log_level; + bt_event_class_status status; + bt_field_class *out_specific_context_fc, *out_payload_fc; + const bt_field_class *in_event_specific_context, *in_event_payload; + int ret = 0; + + BT_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) { + status = bt_event_class_set_name(out_event_class, in_event_class_name); + if (status != BT_EVENT_CLASS_STATUS_OK) { + BT_LOGE("Error setting event class' name: ec-addr=%p, " + "name=%s", out_event_class, in_event_class_name); + ret = -1; + goto error; + } + } + + /* Copy event class loglevel. */ + prop_avail = bt_event_class_get_log_level(in_event_class, &log_level); + if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) { + bt_event_class_set_log_level(out_event_class, + log_level); + } + + /* Copy event class emf uri. */ + in_emf_uri = bt_event_class_get_emf_uri(in_event_class); + if (in_emf_uri) { + status = bt_event_class_set_emf_uri(out_event_class, in_emf_uri); + if (status != BT_EVENT_CLASS_STATUS_OK) { + BT_LOGE("Error setting event class' emf uri: ec-addr=%p, " + "emf uri=%s", out_event_class, in_emf_uri); + ret = -1; + goto error; + } + } + + 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) { + /* Copy the specific context of this event class. */ + out_specific_context_fc = create_field_class_copy(md_maps, + in_event_specific_context); + + copy_field_class_content(md_maps, + in_event_specific_context, out_specific_context_fc); + if (ret) { + goto error; + } + /* + * Add the output specific context to the output event + * class. + */ + status = bt_event_class_set_specific_context_field_class( + out_event_class, out_specific_context_fc); + if (status != BT_EVENT_CLASS_STATUS_OK) { + BT_LOGE("Error setting event class' specific context " + "field class: ec-addr=%p, ctx-fc-addr=%p", + out_event_class, out_specific_context_fc); + ret = -1; + goto error; + } + } + + /* + * 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) { + /* Copy the payload of this event class. */ + out_payload_fc = create_field_class_copy(md_maps, + in_event_payload); + copy_field_class_content(md_maps, + in_event_payload, out_payload_fc); + if (ret) { + goto error; + } + + /* Add the output payload to the output event class. */ + status = bt_event_class_set_payload_field_class( + out_event_class, out_payload_fc); + if (status != BT_EVENT_CLASS_STATUS_OK) { + BT_LOGE("Error setting event class' payload " + "field class: ec-addr=%p, payload-fc-addr=%p", + out_event_class, out_payload_fc); + ret = -1; + goto error; + } + } + + BT_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p", + in_event_class, out_event_class); +error: + return ret; +} + +BT_HIDDEN +int 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) +{ + bt_field_class_status status; + bt_field_class *debug_field_class = NULL, *bin_field_class = NULL, + *func_field_class = NULL, *src_field_class = NULL; + int ret = 0; + + BT_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. */ + ret = copy_field_class_content(md_maps, in_field_class, out_field_class); + if (ret) { + 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)) { + /* + * 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_LOGE_STR("Failed to create debug_info structure."); + ret = -1; + goto error; + } + + bin_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!bin_field_class) { + BT_LOGE_STR("Failed to create string for field=bin."); + ret = -1; + goto error; + } + + func_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!func_field_class) { + BT_LOGE_STR("Failed to create string for field=func."); + ret = -1; + goto error; + } + + src_field_class = bt_field_class_string_create( + md_maps->output_trace_class); + if (!src_field_class) { + BT_LOGE_STR("Failed to create string for field=src."); + ret = -1; + goto error; + } + + status = bt_field_class_structure_append_member( + debug_field_class, "bin", bin_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add a field to debug_info " + "struct: field=bin."); + ret = -1; + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class); + + status = bt_field_class_structure_append_member( + debug_field_class, "func", func_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add a field to debug_info " + "struct: field=func."); + ret = -1; + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class); + + status = bt_field_class_structure_append_member( + debug_field_class, "src", src_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add a field to debug_info " + "struct: field=src."); + ret = -1; + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class); + + /*Add the filled debug-info field class to the common context. */ + status = bt_field_class_structure_append_member(out_field_class, + debug_info_fc_name, + debug_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add debug_info field to " + "event common context."); + ret = -1; + goto error; + } + BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class); + } + BT_LOGD("Copied content of event common context field class: " + "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); + 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 ret; +} + +BT_HIDDEN +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); +} + +BT_HIDDEN +int 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/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h new file mode 100644 index 00000000..3901b26d --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h @@ -0,0 +1,64 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H + +/* + * Babeltrace - Trace IR metadata object copy + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "trace-ir-mapping.h" + +BT_HIDDEN +int copy_trace_class_content(const bt_trace_class *in_trace_class, + bt_trace_class *out_trace_class); + +BT_HIDDEN +int copy_stream_class_content(struct trace_ir_maps *trace_ir_maps, + const bt_stream_class *in_stream_class, + bt_stream_class *out_stream_class); + +BT_HIDDEN +int copy_event_class_content(struct trace_ir_maps *trace_ir_maps, + const bt_event_class *in_event_class, + bt_event_class *out_event_class); + +BT_HIDDEN +int 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); + +BT_HIDDEN +int 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_HIDDEN +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_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H */ diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c new file mode 100644 index 00000000..df6e26d1 --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c @@ -0,0 +1,735 @@ +/* + * Babeltrace - Trace IR field copy + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-FC-COPY" +#include "logging.h" + +#include +#include +#include +#include + +#include "trace-ir-metadata-copy.h" +#include "trace-ir-metadata-field-class-copy.h" + +/* + * This fonction walks througth 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(const bt_field_path *fp, + const bt_field_class *fc) +{ + uint64_t i, fp_index_count; + const bt_field_class *curr_fc; + + BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE); + BT_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p", + fp, fc); + + fp_index_count = bt_field_path_get_index_count(fp); + curr_fc = fc; + for (i = 0; i < fp_index_count; i++) { + bt_field_class_type fc_type = bt_field_class_get_type(curr_fc); + uint64_t curr_index = bt_field_path_get_index_by_index(fp, i); + + switch (fc_type) { + case BT_FIELD_CLASS_TYPE_STRUCTURE: + { + const bt_field_class_structure_member *member = + bt_field_class_structure_borrow_member_by_index_const( + curr_fc, curr_index); + curr_fc = bt_field_class_structure_member_borrow_field_class_const( + member); + break; + } + case BT_FIELD_CLASS_TYPE_VARIANT: + { + const bt_field_class_variant_option *option = + bt_field_class_variant_borrow_option_by_index_const( + curr_fc, curr_index); + curr_fc = bt_field_class_variant_option_borrow_field_class_const( + option); + break; + } + default: + 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_scope fp_scope; + + BT_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_SCOPE_PACKET_CONTEXT: + fc = walk_field_path(fp, fc_resolving_ctx->packet_context); + break; + case BT_SCOPE_EVENT_COMMON_CONTEXT: + fc = walk_field_path(fp, fc_resolving_ctx->event_common_context); + break; + case BT_SCOPE_EVENT_SPECIFIC_CONTEXT: + fc = walk_field_path(fp, fc_resolving_ctx->event_specific_context); + break; + case BT_SCOPE_EVENT_PAYLOAD: + fc = walk_field_path(fp, fc_resolving_ctx->event_payload); + break; + default: + 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 +int 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_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_LOGD("Copied content of unsigned integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + return 0; +} + +static inline +int 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_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_LOGD("Copied content of signed integer field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + return 0; +} + +BT_HIDDEN +int 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) +{ + uint64_t i, enum_mapping_count; + int ret = 0; + + BT_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_field_class_unsigned_enumeration_mapping_ranges *ranges; + uint64_t range_index, range_count; + + /* Get the ranges and the range count. */ + bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( + in_field_class, i, &label, &ranges); + range_count = + bt_field_class_unsigned_enumeration_mapping_ranges_get_range_count( + ranges); + /* + * Iterate over all the ranges to add them to copied field + * class. + */ + for (range_index = 0; range_index < range_count; range_index++) { + uint64_t lower, upper; + bt_field_class_status status; + bt_field_class_unsigned_enumeration_mapping_ranges_get_range_by_index( + ranges, range_index, &lower, &upper); + + BT_LOGD("Copying range in enumeration field class: " + "label=%s, lower=%"PRId64", upper=%"PRId64, + label, lower, upper); + + /* Add the label and its range to the copy field class. */ + status = bt_field_class_unsigned_enumeration_map_range( + out_field_class, label, lower, upper); + + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add range to unsigned " + "enumeration."); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); + ret = -1; + goto error; + } + } + } + + BT_LOGD("Copied content of unsigned enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + +error: + return ret; +} + +static inline +int 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) +{ + uint64_t i, enum_mapping_count; + int ret = 0; + + BT_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_field_class_signed_enumeration_mapping_ranges *ranges; + uint64_t range_index, range_count; + + /* Get the ranges and the range count. */ + bt_field_class_signed_enumeration_borrow_mapping_by_index_const( + in_field_class, i, &label, &ranges); + range_count = + bt_field_class_signed_enumeration_mapping_ranges_get_range_count( + ranges); + /* + * Iterate over all the ranges to add them to copied field + * class. + */ + for (range_index = 0; range_index < range_count; range_index++) { + int64_t lower, upper; + bt_field_class_status status; + bt_field_class_signed_enumeration_mapping_ranges_get_range_by_index( + ranges, range_index, &lower, &upper); + + BT_LOGD("Copying range in enumeration field class: " + "label=%s, lower=%ld, upper=%ld", + label, lower, upper); + + /* Add the label and its range to the copy field class. */ + status = bt_field_class_signed_enumeration_map_range( + out_field_class, label, lower, upper); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Failed to add range to signed " + "enumeration."); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); + ret = -1; + goto error; + } + } + } + + BT_LOGD("Copied content of signed enumeration field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + +error: + return ret; +} + +static inline +int field_class_real_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + BT_LOGD("Copying content of real field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + + bt_field_class_real_set_is_single_precision(out_field_class, + bt_field_class_real_is_single_precision(in_field_class)); + + BT_LOGD("Copied content real field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + + return 0; +} + +static inline +int field_class_structure_copy( + struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class, + bt_field_class *out_field_class) +{ + uint64_t i, struct_member_count; + bt_field_class_status status; + int ret = 0; + + BT_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++) { + const bt_field_class_structure_member *member; + const char *member_name; + const bt_field_class *member_fc; + bt_field_class *out_member_field_class; + + member = bt_field_class_structure_borrow_member_by_index_const( + in_field_class, i); + member_fc = bt_field_class_structure_member_borrow_field_class_const( + member); + member_name = bt_field_class_structure_member_get_name(member); + BT_LOGD("Copying structure field class's field: " + "index=%" PRId64 ", " + "member-fc-addr=%p, field-name=\"%s\"", + i, member_fc, member_name); + + out_member_field_class = create_field_class_copy(md_maps, + member_fc); + if (!out_member_field_class) { + BT_LOGE("Cannot copy structure field class's field: " + "index=%" PRId64 ", " + "field-fc-addr=%p, field-name=\"%s\"", + i, member_fc, member_name); + ret = -1; + goto error; + } + ret = copy_field_class_content(md_maps, member_fc, + out_member_field_class); + if (ret) { + goto error; + } + + status = bt_field_class_structure_append_member(out_field_class, + member_name, out_member_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE("Cannot append structure field class's field: " + "index=%" PRId64 ", " + "field-fc-addr=%p, field-name=\"%s\"", + i, member_fc, member_name); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_field_class); + ret = -1; + goto error; + } + } + + BT_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p", + in_field_class, out_field_class); + +error: + return ret; +} + +static inline +int 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_field_class *out_tag_field_class; + uint64_t i, variant_option_count; + const bt_field_path *tag_fp; + const bt_field_class *tag_fc; + int ret = 0; + + BT_LOGD("Copying content of variant field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + + tag_fp = bt_field_class_variant_borrow_selector_field_path_const( + in_field_class); + if (tag_fp) { + tag_fc = resolve_field_path_to_field_class(tag_fp, + md_maps); + + out_tag_field_class = g_hash_table_lookup( + md_maps->field_class_map, tag_fc); + if (!out_tag_field_class) { + BT_LOGE_STR("Cannot find the tag field class."); + ret = -1; + goto error; + } + bt_field_class_variant_set_selector_field_class(out_field_class, + out_tag_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 *option_fc; + const char *option_name; + bt_field_class *out_option_field_class; + bt_field_class_status status; + const bt_field_class_variant_option *option; + + option = bt_field_class_variant_borrow_option_by_index_const( + in_field_class, i); + option_fc = bt_field_class_variant_option_borrow_field_class_const( + option); + option_name = bt_field_class_variant_option_get_name(option); + out_option_field_class = create_field_class_copy_internal( + md_maps, option_fc); + if (!out_option_field_class) { + BT_LOGE_STR("Cannot copy field class."); + ret = -1; + goto error; + } + ret = copy_field_class_content_internal(md_maps, option_fc, + out_option_field_class); + if (ret) { + BT_LOGE_STR("Error copying content of option variant " + "field class'"); + goto error; + } + + status = bt_field_class_variant_append_option( + out_field_class, option_name, + out_option_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Cannot append option to variant field class'"); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + ret = -1; + goto error; + } + } + + BT_LOGD("Copied content of variant field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + +error: + return ret; +} + +static inline +int 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_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_LOGD("Copied content of static array field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + + return 0; +} + +static inline +int 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) +{ + const bt_field_class *len_fc; + const bt_field_path *len_fp; + bt_field_class_status status; + bt_field_class *out_len_field_class; + int ret = 0; + + BT_LOGD("Copying content of dynamic array field class: " + "in-fc-addr=%p, out-fc-addr=%p", + in_field_class, out_field_class); + + len_fp = bt_field_class_dynamic_array_borrow_length_field_path_const( + in_field_class); + + if (len_fp) { + BT_LOGD("Copying dynamic array length field class using " + "field path: in-len-fp=%p", len_fp); + len_fc = resolve_field_path_to_field_class( + len_fp, md_maps); + out_len_field_class = g_hash_table_lookup( + md_maps->field_class_map, len_fc); + if (!out_len_field_class) { + BT_LOGE_STR("Cannot find the output matching length" + "field class."); + ret = -1; + goto error; + } + + status = bt_field_class_dynamic_array_set_length_field_class( + out_field_class, out_len_field_class); + if (status != BT_FIELD_CLASS_STATUS_OK) { + BT_LOGE_STR("Cannot set dynamic array field class' " + "length field class."); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_len_field_class); + ret = -1; + goto error; + } + } + + BT_LOGD("Copied dynamic array field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + +error: + return ret; +} + +static inline +int 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_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_LOGD("Copied content of string field class: in-fc-addr=%p, " + "out-fc-addr=%p", in_field_class, out_field_class); + + return 0; +} + +static +bt_field_class *copy_field_class_array_element(struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_elem_fc) +{ + int ret; + bt_field_class *out_elem_fc = + create_field_class_copy_internal(md_maps, in_elem_fc); + if (!out_elem_fc) { + BT_LOGE("Error creating output elem field class " + "from input elem field class for static array: " + "in-fc-addr=%p", in_elem_fc); + goto error; + } + + ret = copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc); + if (ret) { + BT_LOGE("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 error; + } + +error: + return out_elem_fc; +} + +BT_HIDDEN +bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps *md_maps, + const bt_field_class *in_field_class) +{ + bt_field_class *out_field_class = NULL; + + BT_LOGD("Creating bare field class based on field class: in-fc-addr=%p", + in_field_class); + + switch(bt_field_class_get_type(in_field_class)) { + case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: + out_field_class = bt_field_class_unsigned_integer_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: + out_field_class = bt_field_class_signed_integer_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: + out_field_class = bt_field_class_unsigned_enumeration_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: + out_field_class = bt_field_class_signed_enumeration_create( + md_maps->output_trace_class); + break; + case BT_FIELD_CLASS_TYPE_REAL: + out_field_class = bt_field_class_real_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_static_array_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_static_array_create( + md_maps->output_trace_class, + out_elem_fc, array_len); + break; + } + case 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_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_dynamic_array_create( + md_maps->output_trace_class, + out_elem_fc); + break; + } + case BT_FIELD_CLASS_TYPE_VARIANT: + out_field_class = bt_field_class_variant_create( + md_maps->output_trace_class); + break; + default: + abort(); + } + + /* + * Add mapping from in_field_class to out_field_class. This simplifies + * the resolution of field paths in variant and dynamic array field + * classes. + */ + g_hash_table_insert(md_maps->field_class_map, + (gpointer) in_field_class, out_field_class); + +error: + if(out_field_class){ + BT_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_LOGE("Error creating output field class from input field " + "class: in-fc-addr=%p", in_field_class); + } + + return out_field_class; +} + +BT_HIDDEN +int 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) +{ + int ret = 0; + switch(bt_field_class_get_type(in_field_class)) { + case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: + ret = field_class_unsigned_integer_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: + ret = field_class_signed_integer_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: + ret = field_class_unsigned_enumeration_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: + ret = field_class_signed_enumeration_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_REAL: + ret = field_class_real_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_STRING: + ret = field_class_string_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_STRUCTURE: + ret = field_class_structure_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: + ret = field_class_static_array_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: + ret = field_class_dynamic_array_copy(md_maps, + in_field_class, out_field_class); + break; + case BT_FIELD_CLASS_TYPE_VARIANT: + ret = field_class_variant_copy(md_maps, + in_field_class, out_field_class); + break; + default: + abort(); + } + + return ret; +} diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h new file mode 100644 index 00000000..855e6cdc --- /dev/null +++ b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h @@ -0,0 +1,42 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H + +/* + * Babeltrace - Trace IR metadata field class copy + * + * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2019 Francis Deslauriers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "trace-ir-mapping.h" + +BT_HIDDEN +int 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_HIDDEN +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_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H */ diff --git a/plugins/lttng-utils/debug-info/utils.c b/plugins/lttng-utils/debug-info/utils.c new file mode 100644 index 00000000..d9c5fa50 --- /dev/null +++ b/plugins/lttng-utils/debug-info/utils.c @@ -0,0 +1,117 @@ +/* + * Babeltrace - Debug info utilities + * + * Copyright (c) 2016 Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "utils.h" + +BT_HIDDEN +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; +} + +BT_HIDDEN +bt_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; + bt_bool match = BT_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) { + match = BT_FALSE; + goto end; + } + + if (bt_field_class_integer_get_field_value_range(ip_fc) != 64) { + 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 = BT_TRUE; + +end: + return match; +} diff --git a/plugins/lttng-utils/debug-info/utils.h b/plugins/lttng-utils/debug-info/utils.h new file mode 100644 index 00000000..5f65a470 --- /dev/null +++ b/plugins/lttng-utils/debug-info/utils.h @@ -0,0 +1,44 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H +/* + * Babeltrace - Debug Info Utilities + * + * Copyright 2016 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "trace-ir-mapping.h" + +/* + * Return the location of a path's file (the last element of the path). + * Returns the original path on error. + */ +BT_HIDDEN +const char *get_filename_from_path(const char *path); + +BT_HIDDEN +bt_bool is_event_common_ctx_dbg_info_compatible( + const bt_field_class *in_field_class, + const char *debug_info_field_class_name); + +#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H */ diff --git a/plugins/lttng-utils/dwarf.c b/plugins/lttng-utils/dwarf.c deleted file mode 100644 index 534d2883..00000000 --- a/plugins/lttng-utils/dwarf.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * dwarf.c - * - * Babeltrace - DWARF Information Reader - * - * Copyright 2015 Antoine Busque - * - * Author: Antoine Busque - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include "dwarf.h" - -BT_HIDDEN -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; -} - -BT_HIDDEN -void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu) -{ - g_free(cu); -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -void bt_dwarf_die_destroy(struct bt_dwarf_die *die) -{ - if (!die) { - return; - } - - g_free(die->dwarf_die); - g_free(die); -} - -BT_HIDDEN -int bt_dwarf_die_has_children(struct bt_dwarf_die *die) -{ - return dwarf_haschildren(die->dwarf_die); -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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; -} - -BT_HIDDEN -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/plugins/lttng-utils/dwarf.h b/plugins/lttng-utils/dwarf.h deleted file mode 100644 index 707431f9..00000000 --- a/plugins/lttng-utils/dwarf.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef _BABELTRACE_DWARF_H -#define _BABELTRACE_DWARF_H - -/* - * Babeltrace - DWARF Information Reader - * - * Copyright 2015 Antoine Busque - * - * Author: Antoine Busque - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include - -/* - * 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. - */ -BT_HIDDEN -struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info); - -/** - * Destroy the given bt_dwarf_cu instance. - * - * @param cu bt_dwarf_cu instance - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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. - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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. - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 - */ -BT_HIDDEN -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 succes, -1 on failure - */ -BT_HIDDEN -int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr, - bool *contains); - -#endif /* _BABELTRACE_DWARF_H */ diff --git a/plugins/lttng-utils/logging.c b/plugins/lttng-utils/logging.c deleted file mode 100644 index 78c2e17f..00000000 --- a/plugins/lttng-utils/logging.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017 Philippe Proulx - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level -#include - -BT_LOG_INIT_LOG_LEVEL(bt_plugin_lttng_utils_debug_info_log_level, - "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL"); diff --git a/plugins/lttng-utils/logging.h b/plugins/lttng-utils/logging.h deleted file mode 100644 index b77a02f9..00000000 --- a/plugins/lttng-utils/logging.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H -#define PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H - -/* - * Copyright (c) 2017 Philippe Proulx - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level -#include - -BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_lttng_utils_debug_info_log_level); - -#endif /* PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H */ diff --git a/plugins/lttng-utils/plugin.c b/plugins/lttng-utils/plugin.c index 655e30f8..0f100da2 100644 --- a/plugins/lttng-utils/plugin.c +++ b/plugins/lttng-utils/plugin.c @@ -27,7 +27,7 @@ */ #include -#include "debug-info.h" +#include "debug-info/debug-info.h" #ifndef BT_BUILT_IN_PLUGINS BT_PLUGIN_MODULE(); diff --git a/plugins/lttng-utils/trace-ir-data-copy.c b/plugins/lttng-utils/trace-ir-data-copy.c deleted file mode 100644 index 78f611cb..00000000 --- a/plugins/lttng-utils/trace-ir-data-copy.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Babeltrace - Trace IR data object copy - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-DATA-COPY" -#include "logging.h" - -#include -#include - -#include - -#include "trace-ir-data-copy.h" - -BT_HIDDEN -void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace) -{ - bt_trace_status status; - const char *trace_name; - - BT_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) { - status = bt_trace_set_name(out_trace, trace_name); - if (status != BT_TRACE_STATUS_OK) { - BT_LOGE("Cannot set trace's name: trace-addr=%p, name=\"%s\"", - out_trace, trace_name); - goto end; - } - } - - BT_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p", - in_trace, out_trace); -end: - return; -} - -BT_HIDDEN -void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream) -{ - const char *stream_name; - bt_stream_status status; - - BT_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) { - status = bt_stream_set_name(out_stream, stream_name); - if (status != BT_STREAM_STATUS_OK) { - BT_LOGE("Cannot set stream's name: stream-addr=%p, " - "name=%s", out_stream, stream_name); - goto end; - } - } - - BT_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p", - in_stream, out_stream); -end: - return; -} - -BT_HIDDEN -void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet) -{ - const bt_field *in_context_field; - bt_field *out_context_field; - - BT_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); - copy_field_content(in_context_field, out_context_field); - } - - BT_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p", - in_packet, out_packet); - return; -} - -BT_HIDDEN -void copy_event_content(const bt_event *in_event, bt_event *out_event) -{ - 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_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(out_common_ctx_field); - copy_field_content(in_common_ctx_field, - out_common_ctx_field); - } - - 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(out_specific_ctx_field); - copy_field_content(in_specific_ctx_field, - out_specific_ctx_field); - } - - 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(out_payload_field); - copy_field_content(in_payload_field, - out_payload_field); - } - - BT_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p", - in_event, out_event); -} - -BT_HIDDEN -void copy_field_content(const bt_field *in_field, bt_field *out_field) -{ - 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(in_fc_type == out_fc_type); - - BT_LOGD("Copying content of field: in-f-addr=%p, out-f-addr=%p", - in_field, out_field); - switch (in_fc_type) { - case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: - case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: - bt_field_unsigned_integer_set_value(out_field, - bt_field_unsigned_integer_get_value(in_field)); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: - case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: - bt_field_signed_integer_set_value(out_field, - bt_field_signed_integer_get_value(in_field)); - break; - case BT_FIELD_CLASS_TYPE_REAL: - bt_field_real_set_value(out_field, - bt_field_real_get_value(in_field)); - break; - case BT_FIELD_CLASS_TYPE_STRING: - { - const char *str = bt_field_string_get_value(in_field); - bt_field_status status = bt_field_string_set_value(out_field, str); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set string field's value: " - "str-field-addr=%p, str=%s" PRId64, - out_field, str); - } - break; - } - case 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); - - copy_field_content(in_member_field, - out_member_field); - } - break; - } - case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: - /* fall through */ - case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: - { - const bt_field *in_element_field; - bt_field *out_element_field; - uint64_t i, array_len; - bt_field_status status; - - array_len = bt_field_array_get_length(in_field); - - if (in_fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY) { - status = bt_field_dynamic_array_set_length(out_field, - array_len); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot set dynamic array field's " - "length field: field-addr=%p, " - "length=%" PRIu64, out_field, array_len); - } - } - - 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); - copy_field_content(in_element_field, out_element_field); - } - break; - } - case BT_FIELD_CLASS_TYPE_VARIANT: - { - bt_field_status 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_field_index( - in_field); - status = bt_field_variant_select_option_field(out_field, - in_selected_option_idx); - if (status != BT_FIELD_STATUS_OK) { - BT_LOGE("Cannot select variant field's option field: " - "var-field-addr=%p, opt-index=%" PRId64, - out_field, in_selected_option_idx); - } - - 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); - - copy_field_content(in_option_field, out_option_field); - - break; - } - default: - abort(); - } - BT_LOGD("Copied content of field: in-f-addr=%p, out-f-addr=%p", - in_field, out_field); -} diff --git a/plugins/lttng-utils/trace-ir-data-copy.h b/plugins/lttng-utils/trace-ir-data-copy.h deleted file mode 100644 index 97eface5..00000000 --- a/plugins/lttng-utils/trace-ir-data-copy.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H - -/* - * Babeltrace - Trace IR data object copy - * - * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include - -#include "trace-ir-mapping.h" - -BT_HIDDEN -void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace); -BT_HIDDEN -void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream); -BT_HIDDEN -void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet); -BT_HIDDEN -void copy_event_content(const bt_event *in_event, bt_event *out_event); -BT_HIDDEN -void copy_field_content(const bt_field *in_field, bt_field *out_field); - -#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H */ diff --git a/plugins/lttng-utils/trace-ir-mapping.c b/plugins/lttng-utils/trace-ir-mapping.c deleted file mode 100644 index 3ed687c6..00000000 --- a/plugins/lttng-utils/trace-ir-mapping.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Babeltrace - Mapping of IR metadata and data object between input and output - * trace - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-MAPPING" -#include "logging.h" - -#include - -#include -#include -/* For bt_property_availability */ -#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) -{ - int ret; - bt_trace_class *out_trace_class; - - BT_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class); - - BT_ASSERT(ir_maps); - BT_ASSERT(in_trace_class); - - /* Create the ouput trace class. */ - out_trace_class = bt_trace_class_create(ir_maps->self_comp); - if (!out_trace_class) { - BT_LOGE_STR("Error create output trace class"); - goto end; - } - - /* If not, create a new one and add it to the mapping. */ - ret = copy_trace_class_content(in_trace_class, out_trace_class); - if (ret) { - BT_LOGE_STR("Error copy content to output trace class"); - out_trace_class = NULL; - goto end; - } - - BT_LOGD("Created new mapped trace class: in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, out_trace_class); - -end: - return out_trace_class; -} - -static -bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps, - const bt_trace *in_trace) -{ - bt_trace *out_trace; - const bt_trace_class *in_trace_class; - struct trace_ir_metadata_maps *metadata_maps; - - BT_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) { - metadata_maps->output_trace_class = - create_new_mapped_trace_class(ir_maps, in_trace_class); - if (!metadata_maps->output_trace_class) { - out_trace = NULL; - goto end; - } - } - - out_trace = bt_trace_create(metadata_maps->output_trace_class); - if (!out_trace) { - BT_LOGE_STR("Error create output trace"); - goto end; - } - - /* If not, create a new one and add it to the mapping. */ - copy_trace_content(in_trace, out_trace); - - BT_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p", - in_trace, out_trace); -end: - return out_trace; -} - -static -bt_stream_class *borrow_mapped_stream_class(struct trace_ir_metadata_maps *md_maps, - const bt_stream_class *in_stream_class) -{ - BT_ASSERT(md_maps); - BT_ASSERT(in_stream_class); - - return g_hash_table_lookup(md_maps->stream_class_map, - (gpointer) in_stream_class); -} - -static -bt_stream_class *create_new_mapped_stream_class(struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class) -{ - int ret; - bt_stream_class *out_stream_class; - struct trace_ir_metadata_maps *md_maps; - - BT_LOGD("Creating new mapped stream class: in-sc-addr=%p", - in_stream_class); - - md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, - in_stream_class); - - BT_ASSERT(md_maps); - BT_ASSERT(in_stream_class); - BT_ASSERT(!borrow_mapped_stream_class(md_maps, in_stream_class)); - - /* Create an out_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_LOGE_STR("Error create output stream class"); - goto end; - } - - /* If not, create a new one and add it to the mapping. */ - ret = copy_stream_class_content(ir_maps, in_stream_class, - out_stream_class); - if (ret) { - BT_LOGE_STR("Error copy content to output stream class"); - out_stream_class = NULL; - goto end; - } - - g_hash_table_insert(md_maps->stream_class_map, - (gpointer) in_stream_class, out_stream_class); - - BT_LOGD("Created new mapped stream class: in-sc-addr=%p, out-sc-addr=%p", - in_stream_class, out_stream_class); - -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(d_maps); - BT_ASSERT(in_stream); - - return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream); -} - -BT_HIDDEN -bt_stream *trace_ir_mapping_create_new_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream) -{ - struct trace_ir_data_maps *d_maps; - struct trace_ir_metadata_maps *md_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_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream); - - BT_ASSERT(ir_maps); - BT_ASSERT(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) { - d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace); - if (!d_maps->output_trace) { - goto end; - } - } - - 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); - if (bt_stream_class_default_clock_is_always_known(in_stream_class) - == BT_FALSE) { - BT_LOGE("Stream class default clock class is not always " - "known: in-sc-addr=%p", in_stream_class); - goto end; - } - - md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class); - out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class); - if (!out_stream_class) { - out_stream_class = create_new_mapped_stream_class(ir_maps, - in_stream_class); - if (!out_stream_class) { - goto end; - } - } - BT_ASSERT(out_stream_class); - - out_stream = bt_stream_create_with_id(out_stream_class, - d_maps->output_trace, bt_stream_get_id(in_stream)); - if (!out_stream) { - BT_LOGE_STR("Error creating output stream"); - goto end; - } - /* - * Release our ref since the trace object will be managing the life - * time of the stream objects. - */ - - copy_stream_content(in_stream, out_stream); - - g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream, - out_stream); - - BT_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p", - in_stream, out_stream); - -end: - return out_stream; -} - -BT_HIDDEN -bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps, - const bt_stream *in_stream) -{ - BT_ASSERT(ir_maps); - BT_ASSERT(in_stream); - struct trace_ir_data_maps *d_maps; - - 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_HIDDEN -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 *out_event_class; - const bt_trace_class *in_trace_class; - const bt_stream_class *in_stream_class; - bt_stream_class *out_stream_class; - struct trace_ir_metadata_maps *md_maps; - int ret; - - BT_LOGD("Creating new mapped event class: in-ec-addr=%p", - in_event_class); - - BT_ASSERT(ir_maps); - BT_ASSERT(in_event_class); - - in_trace_class = bt_stream_class_borrow_trace_class_const( - bt_event_class_borrow_stream_class_const( - in_event_class)); - - md_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, in_trace_class); - - BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class)); - - in_stream_class = - bt_event_class_borrow_stream_class_const(in_event_class); - BT_ASSERT(in_stream_class); - - /* Get the right output stream class to add the new event class to. */ - out_stream_class = borrow_mapped_stream_class(md_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_LOGE_STR("Error creating output event class"); - goto end; - } - - /* If not, create a new one and add it to the mapping. */ - ret = copy_event_class_content(ir_maps, in_event_class, - out_event_class); - if (ret) { - BT_LOGE_STR("Error copy content to output event class"); - out_event_class = NULL; - goto end; - } - - g_hash_table_insert(md_maps->event_class_map, - (gpointer) in_event_class, out_event_class); - - BT_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p", - in_event_class, out_event_class); - -end: - return out_event_class; -} - -BT_HIDDEN -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(ir_maps); - BT_ASSERT(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(d_maps); - BT_ASSERT(in_packet); - - return g_hash_table_lookup(d_maps->packet_map, - (gpointer) in_packet); -} - -BT_HIDDEN -bt_packet *trace_ir_mapping_create_new_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet) -{ - struct trace_ir_data_maps *d_maps; - const bt_trace *in_trace; - const bt_stream *in_stream; - bt_packet *out_packet; - bt_stream *out_stream; - - BT_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. */ - 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_LOGE_STR("Error create output packet"); - goto end; - } - - /* - * Release our ref since the stream object will be managing the life - * time of the packet objects. - */ - copy_packet_content(in_packet, out_packet); - - g_hash_table_insert(d_maps->packet_map, - (gpointer) in_packet, out_packet); - - BT_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p", - in_packet, out_packet); - -end: - return out_packet; -} - -BT_HIDDEN -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(ir_maps); - BT_ASSERT(in_packet); - - d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet); - - return borrow_mapped_packet(d_maps, in_packet); -} - -BT_HIDDEN -void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps, - const bt_packet *in_packet) -{ - gboolean ret; - - struct trace_ir_data_maps *d_maps; - 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); -} - -BT_HIDDEN -void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps, - const bt_stream *in_stream) -{ - gboolean ret; - struct trace_ir_data_maps *d_maps; - - 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) -{ - struct trace_ir_data_maps *d_maps = - g_new0(struct trace_ir_data_maps, 1); - if (!d_maps) { - BT_LOGE_STR("Error allocating trace_ir_maps"); - goto error; - } - - 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); - - bt_trace_add_destruction_listener(in_trace, trace_ir_data_maps_remove_func, - ir_maps, &d_maps->destruction_listener_id); -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) -{ - struct trace_ir_metadata_maps *md_maps = - g_new0(struct trace_ir_metadata_maps, 1); - if (!md_maps) { - BT_LOGE_STR("Error allocating trace_ir_maps"); - goto error; - } - - 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_LOGE_STR("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); - - bt_trace_class_add_destruction_listener(in_trace_class, - trace_ir_metadata_maps_remove_func, - ir_maps, &md_maps->destruction_listener_id); -error: - return md_maps; -} - -BT_HIDDEN -void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps) -{ - bt_trace_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_STATUS_OK) { - BT_LOGD("Trace destruction listener removal failed."); - } - - g_free(maps); -} - -BT_HIDDEN -void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps) -{ - bt_trace_class_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); - } - - if (maps->fc_resolving_ctx) { - 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_STATUS_OK) { - BT_LOGD("Trace destruction listener removal failed."); - } - - 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); - } -} - -BT_HIDDEN -void trace_ir_maps_destroy(struct trace_ir_maps *maps) -{ - if (!maps) { - return; - } - - if (maps->debug_info_field_class_name) { - 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); -} - -BT_HIDDEN -struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, - const char *debug_info_field_name) -{ - struct trace_ir_maps *trace_ir_maps = - g_new0(struct trace_ir_maps, 1); - if (!trace_ir_maps) { - BT_LOGE_STR("Error allocating trace_ir_maps"); - goto error; - } - - /* Copy debug info field name received from the user. */ - trace_ir_maps->debug_info_field_class_name = - g_strdup(debug_info_field_name); - if (!trace_ir_maps->debug_info_field_class_name) { - BT_LOGE_STR("Cannot copy debug info field name"); - goto error; - } - - trace_ir_maps->self_comp = self_comp; - - trace_ir_maps->data_maps = g_hash_table_new_full(g_direct_hash, - g_direct_equal, (GDestroyNotify) NULL, - (GDestroyNotify) trace_ir_data_maps_destroy); - - trace_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(trace_ir_maps); - trace_ir_maps = NULL; -end: - return trace_ir_maps; -} diff --git a/plugins/lttng-utils/trace-ir-mapping.h b/plugins/lttng-utils/trace-ir-mapping.h deleted file mode 100644 index 3601e81e..00000000 --- a/plugins/lttng-utils/trace-ir-mapping.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H -/* - * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include - -#include -#include - -#include "debug-info.h" - -/* 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 { - 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; - - uint64_t destruction_listener_id; -}; - -struct trace_ir_data_maps { - 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; - - uint64_t destruction_listener_id; -}; - -struct trace_ir_maps { - /* - * 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; -}; - -BT_HIDDEN -struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp, - const char *debug_info_field_name); - -BT_HIDDEN -void trace_ir_maps_clear(struct trace_ir_maps *maps); - -BT_HIDDEN -void trace_ir_maps_destroy(struct trace_ir_maps *maps); - -BT_HIDDEN -struct trace_ir_data_maps *trace_ir_data_maps_create( - struct trace_ir_maps *ir_maps, - const bt_trace *in_trace); - -BT_HIDDEN -void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps); - -BT_HIDDEN -struct trace_ir_metadata_maps *trace_ir_metadata_maps_create( - struct trace_ir_maps *ir_maps, - const bt_trace_class *in_trace_class); - -BT_HIDDEN -void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps); - -BT_HIDDEN -bt_stream *trace_ir_mapping_create_new_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -BT_HIDDEN -bt_stream *trace_ir_mapping_borrow_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -BT_HIDDEN -void trace_ir_mapping_remove_mapped_stream( - struct trace_ir_maps *ir_maps, - const bt_stream *in_stream); - -BT_HIDDEN -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_HIDDEN -bt_event_class *trace_ir_mapping_borrow_mapped_event_class( - struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class); - -BT_HIDDEN -bt_packet *trace_ir_mapping_create_new_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet); - -BT_HIDDEN -bt_packet *trace_ir_mapping_borrow_mapped_packet( - struct trace_ir_maps *ir_maps, - const bt_packet *in_packet); - -BT_HIDDEN -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_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H */ diff --git a/plugins/lttng-utils/trace-ir-metadata-copy.c b/plugins/lttng-utils/trace-ir-metadata-copy.c deleted file mode 100644 index 5655e62d..00000000 --- a/plugins/lttng-utils/trace-ir-metadata-copy.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Babeltrace - Trace IR metadata object copy - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-COPY" -#include "logging.h" - -#include -#include - -#include - -#include "trace-ir-metadata-copy.h" -#include "trace-ir-metadata-field-class-copy.h" -#include "utils.h" - -BT_HIDDEN -int copy_trace_class_content(const bt_trace_class *in_trace_class, - bt_trace_class *out_trace_class) -{ - int ret = 0; - uint64_t i, env_field_count; - const char *in_trace_class_name; - bt_uuid in_uuid; - - BT_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, out_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); - - in_trace_class_name = bt_trace_class_get_name(in_trace_class); - if (in_trace_class_name) { - bt_trace_class_set_name(out_trace_class, in_trace_class_name); - } - - in_uuid = bt_trace_class_get_uuid(in_trace_class); - if (in_uuid) { - bt_trace_class_set_uuid(out_trace_class, in_uuid); - } - - /* - * Go over all the entries in the environment section of the trace class - * and copy the content to the new trace class. - */ - env_field_count = bt_trace_class_get_environment_entry_count(in_trace_class); - for (i = 0; i < env_field_count; i++) { - const char *value_name; - const bt_value *value = NULL; - bt_trace_class_status trace_class_status; - - bt_trace_class_borrow_environment_entry_by_index_const( - in_trace_class, i, &value_name, &value); - - BT_LOGD("Copying trace class environnement entry: " - "index=%" PRId64 ", value-addr=%p, value-name=%s", - i, value, value_name); - - BT_ASSERT(value_name); - BT_ASSERT(value); - - if (bt_value_is_integer(value)) { - trace_class_status = - bt_trace_class_set_environment_entry_integer( - out_trace_class, value_name, - bt_value_integer_get(value)); - } else if (bt_value_is_string(value)) { - trace_class_status = - bt_trace_class_set_environment_entry_string( - out_trace_class, value_name, - bt_value_string_get(value)); - } else { - abort(); - } - - if (trace_class_status != BT_TRACE_CLASS_STATUS_OK) { - ret = -1; - goto error; - } - } - - BT_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p", - in_trace_class, out_trace_class); -error: - return ret; -} - -static -int copy_clock_class_content(const bt_clock_class *in_clock_class, - bt_clock_class *out_clock_class) -{ - bt_clock_class_status status; - const char *clock_class_name, *clock_class_description; - int64_t seconds; - uint64_t cycles; - bt_uuid in_uuid; - int ret = 0; - - BT_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) { - status = bt_clock_class_set_name(out_clock_class, clock_class_name); - if (status != BT_CLOCK_CLASS_STATUS_OK) { - BT_LOGE("Error setting clock class' name cc-addr=%p, name=%p", - out_clock_class, clock_class_name); - out_clock_class = NULL; - ret = -1; - goto error; - } - } - - clock_class_description = bt_clock_class_get_description(in_clock_class); - - if (clock_class_description) { - status = bt_clock_class_set_description(out_clock_class, - clock_class_description); - if (status != BT_CLOCK_CLASS_STATUS_OK) { - BT_LOGE("Error setting clock class' description cc-addr=%p, " - "name=%p", out_clock_class, clock_class_description); - out_clock_class = NULL; - ret = -1; - goto error; - } - } - - 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_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p", - in_clock_class, out_clock_class); - -error: - return ret; -} - -static -bt_clock_class *borrow_mapped_clock_class( - struct trace_ir_metadata_maps *md_maps, - const bt_clock_class *in_clock_class) -{ - BT_ASSERT(md_maps); - BT_ASSERT(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) -{ - bt_clock_class *out_clock_class; - int ret; - - BT_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_LOGE_STR("Cannot create clock class"); - goto end; - } - /* If not, create a new one and add it to the mapping. */ - ret = copy_clock_class_content(in_clock_class, out_clock_class); - if (ret) { - BT_LOGE_STR("Cannot copy clock class"); - goto end; - } - - g_hash_table_insert(md_maps->clock_class_map, - (gpointer) in_clock_class, out_clock_class); - - BT_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; -} - -BT_HIDDEN -int copy_stream_class_content(struct trace_ir_maps *ir_maps, - const bt_stream_class *in_stream_class, - bt_stream_class *out_stream_class) -{ - 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; - bt_stream_class_status status; - const char *in_name; - int ret = 0; - - BT_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) { - /* 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); - } - bt_stream_class_set_default_clock_class(out_stream_class, - out_clock_class); - - } - - in_name = bt_stream_class_get_name(in_stream_class); - if (in_name) { - status = bt_stream_class_set_name(out_stream_class, in_name); - if (status != BT_STREAM_CLASS_STATUS_OK) { - BT_LOGE("Error set stream class name: out-sc-addr=%p, " - "name=%s", out_stream_class, in_name); - ret = -1; - goto error; - } - } - - 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) { - /* Copy packet context. */ - out_packet_context_fc = create_field_class_copy( - md_maps, in_packet_context_fc); - - ret = copy_field_class_content(md_maps, - in_packet_context_fc, out_packet_context_fc); - if (ret) { - ret = -1; - goto error; - } - - status = bt_stream_class_set_packet_context_field_class( - out_stream_class, out_packet_context_fc); - if (status != BT_STREAM_CLASS_STATUS_OK) { - BT_LOGE("Error setting stream class' packet context " - "field class: sc-addr=%p, packet-fc-addr=%p", - out_stream_class, out_packet_context_fc); - ret = -1; - goto error; - } - } - - /* - * 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) { - /* 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); - - ret = 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 (ret) { - goto error; - } - - status = bt_stream_class_set_event_common_context_field_class( - out_stream_class, out_common_context_fc); - if (status != BT_STREAM_CLASS_STATUS_OK) { - BT_LOGE("Error setting stream class' packet context " - "field class: sc-addr=%p, packet-fc-addr=%p", - out_stream_class, out_common_context_fc); - ret = -1; - goto error; - } - } - - /* Set packet snapshot boolean fields. */ - BT_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p", - in_stream_class, out_stream_class); -error: - return ret; -} - -BT_HIDDEN -int copy_event_class_content(struct trace_ir_maps *ir_maps, - const bt_event_class *in_event_class, - bt_event_class *out_event_class) -{ - 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 log_level; - bt_event_class_status status; - bt_field_class *out_specific_context_fc, *out_payload_fc; - const bt_field_class *in_event_specific_context, *in_event_payload; - int ret = 0; - - BT_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) { - status = bt_event_class_set_name(out_event_class, in_event_class_name); - if (status != BT_EVENT_CLASS_STATUS_OK) { - BT_LOGE("Error setting event class' name: ec-addr=%p, " - "name=%s", out_event_class, in_event_class_name); - ret = -1; - goto error; - } - } - - /* Copy event class loglevel. */ - prop_avail = bt_event_class_get_log_level(in_event_class, &log_level); - if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) { - bt_event_class_set_log_level(out_event_class, - log_level); - } - - /* Copy event class emf uri. */ - in_emf_uri = bt_event_class_get_emf_uri(in_event_class); - if (in_emf_uri) { - status = bt_event_class_set_emf_uri(out_event_class, in_emf_uri); - if (status != BT_EVENT_CLASS_STATUS_OK) { - BT_LOGE("Error setting event class' emf uri: ec-addr=%p, " - "emf uri=%s", out_event_class, in_emf_uri); - ret = -1; - goto error; - } - } - - 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) { - /* Copy the specific context of this event class. */ - out_specific_context_fc = create_field_class_copy(md_maps, - in_event_specific_context); - - copy_field_class_content(md_maps, - in_event_specific_context, out_specific_context_fc); - if (ret) { - goto error; - } - /* - * Add the output specific context to the output event - * class. - */ - status = bt_event_class_set_specific_context_field_class( - out_event_class, out_specific_context_fc); - if (status != BT_EVENT_CLASS_STATUS_OK) { - BT_LOGE("Error setting event class' specific context " - "field class: ec-addr=%p, ctx-fc-addr=%p", - out_event_class, out_specific_context_fc); - ret = -1; - goto error; - } - } - - /* - * 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) { - /* Copy the payload of this event class. */ - out_payload_fc = create_field_class_copy(md_maps, - in_event_payload); - copy_field_class_content(md_maps, - in_event_payload, out_payload_fc); - if (ret) { - goto error; - } - - /* Add the output payload to the output event class. */ - status = bt_event_class_set_payload_field_class( - out_event_class, out_payload_fc); - if (status != BT_EVENT_CLASS_STATUS_OK) { - BT_LOGE("Error setting event class' payload " - "field class: ec-addr=%p, payload-fc-addr=%p", - out_event_class, out_payload_fc); - ret = -1; - goto error; - } - } - - BT_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p", - in_event_class, out_event_class); -error: - return ret; -} - -BT_HIDDEN -int 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) -{ - bt_field_class_status status; - bt_field_class *debug_field_class = NULL, *bin_field_class = NULL, - *func_field_class = NULL, *src_field_class = NULL; - int ret = 0; - - BT_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. */ - ret = copy_field_class_content(md_maps, in_field_class, out_field_class); - if (ret) { - 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)) { - /* - * 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_LOGE_STR("Failed to create debug_info structure."); - ret = -1; - goto error; - } - - bin_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!bin_field_class) { - BT_LOGE_STR("Failed to create string for field=bin."); - ret = -1; - goto error; - } - - func_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!func_field_class) { - BT_LOGE_STR("Failed to create string for field=func."); - ret = -1; - goto error; - } - - src_field_class = bt_field_class_string_create( - md_maps->output_trace_class); - if (!src_field_class) { - BT_LOGE_STR("Failed to create string for field=src."); - ret = -1; - goto error; - } - - status = bt_field_class_structure_append_member( - debug_field_class, "bin", bin_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add a field to debug_info " - "struct: field=bin."); - ret = -1; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class); - - status = bt_field_class_structure_append_member( - debug_field_class, "func", func_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add a field to debug_info " - "struct: field=func."); - ret = -1; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class); - - status = bt_field_class_structure_append_member( - debug_field_class, "src", src_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add a field to debug_info " - "struct: field=src."); - ret = -1; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class); - - /*Add the filled debug-info field class to the common context. */ - status = bt_field_class_structure_append_member(out_field_class, - debug_info_fc_name, - debug_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add debug_info field to " - "event common context."); - ret = -1; - goto error; - } - BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class); - } - BT_LOGD("Copied content of event common context field class: " - "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - 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 ret; -} - -BT_HIDDEN -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); -} - -BT_HIDDEN -int 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/plugins/lttng-utils/trace-ir-metadata-copy.h b/plugins/lttng-utils/trace-ir-metadata-copy.h deleted file mode 100644 index 3901b26d..00000000 --- a/plugins/lttng-utils/trace-ir-metadata-copy.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H - -/* - * Babeltrace - Trace IR metadata object copy - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include "trace-ir-mapping.h" - -BT_HIDDEN -int copy_trace_class_content(const bt_trace_class *in_trace_class, - bt_trace_class *out_trace_class); - -BT_HIDDEN -int copy_stream_class_content(struct trace_ir_maps *trace_ir_maps, - const bt_stream_class *in_stream_class, - bt_stream_class *out_stream_class); - -BT_HIDDEN -int copy_event_class_content(struct trace_ir_maps *trace_ir_maps, - const bt_event_class *in_event_class, - bt_event_class *out_event_class); - -BT_HIDDEN -int 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); - -BT_HIDDEN -int 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_HIDDEN -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_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H */ diff --git a/plugins/lttng-utils/trace-ir-metadata-field-class-copy.c b/plugins/lttng-utils/trace-ir-metadata-field-class-copy.c deleted file mode 100644 index df6e26d1..00000000 --- a/plugins/lttng-utils/trace-ir-metadata-field-class-copy.c +++ /dev/null @@ -1,735 +0,0 @@ -/* - * Babeltrace - Trace IR field copy - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-FC-COPY" -#include "logging.h" - -#include -#include -#include -#include - -#include "trace-ir-metadata-copy.h" -#include "trace-ir-metadata-field-class-copy.h" - -/* - * This fonction walks througth 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(const bt_field_path *fp, - const bt_field_class *fc) -{ - uint64_t i, fp_index_count; - const bt_field_class *curr_fc; - - BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE); - BT_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p", - fp, fc); - - fp_index_count = bt_field_path_get_index_count(fp); - curr_fc = fc; - for (i = 0; i < fp_index_count; i++) { - bt_field_class_type fc_type = bt_field_class_get_type(curr_fc); - uint64_t curr_index = bt_field_path_get_index_by_index(fp, i); - - switch (fc_type) { - case BT_FIELD_CLASS_TYPE_STRUCTURE: - { - const bt_field_class_structure_member *member = - bt_field_class_structure_borrow_member_by_index_const( - curr_fc, curr_index); - curr_fc = bt_field_class_structure_member_borrow_field_class_const( - member); - break; - } - case BT_FIELD_CLASS_TYPE_VARIANT: - { - const bt_field_class_variant_option *option = - bt_field_class_variant_borrow_option_by_index_const( - curr_fc, curr_index); - curr_fc = bt_field_class_variant_option_borrow_field_class_const( - option); - break; - } - default: - 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_scope fp_scope; - - BT_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_SCOPE_PACKET_CONTEXT: - fc = walk_field_path(fp, fc_resolving_ctx->packet_context); - break; - case BT_SCOPE_EVENT_COMMON_CONTEXT: - fc = walk_field_path(fp, fc_resolving_ctx->event_common_context); - break; - case BT_SCOPE_EVENT_SPECIFIC_CONTEXT: - fc = walk_field_path(fp, fc_resolving_ctx->event_specific_context); - break; - case BT_SCOPE_EVENT_PAYLOAD: - fc = walk_field_path(fp, fc_resolving_ctx->event_payload); - break; - default: - 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 -int 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_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_LOGD("Copied content of unsigned integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - return 0; -} - -static inline -int 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_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_LOGD("Copied content of signed integer field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - return 0; -} - -BT_HIDDEN -int 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) -{ - uint64_t i, enum_mapping_count; - int ret = 0; - - BT_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_field_class_unsigned_enumeration_mapping_ranges *ranges; - uint64_t range_index, range_count; - - /* Get the ranges and the range count. */ - bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( - in_field_class, i, &label, &ranges); - range_count = - bt_field_class_unsigned_enumeration_mapping_ranges_get_range_count( - ranges); - /* - * Iterate over all the ranges to add them to copied field - * class. - */ - for (range_index = 0; range_index < range_count; range_index++) { - uint64_t lower, upper; - bt_field_class_status status; - bt_field_class_unsigned_enumeration_mapping_ranges_get_range_by_index( - ranges, range_index, &lower, &upper); - - BT_LOGD("Copying range in enumeration field class: " - "label=%s, lower=%"PRId64", upper=%"PRId64, - label, lower, upper); - - /* Add the label and its range to the copy field class. */ - status = bt_field_class_unsigned_enumeration_map_range( - out_field_class, label, lower, upper); - - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add range to unsigned " - "enumeration."); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); - ret = -1; - goto error; - } - } - } - - BT_LOGD("Copied content of unsigned enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - -error: - return ret; -} - -static inline -int 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) -{ - uint64_t i, enum_mapping_count; - int ret = 0; - - BT_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_field_class_signed_enumeration_mapping_ranges *ranges; - uint64_t range_index, range_count; - - /* Get the ranges and the range count. */ - bt_field_class_signed_enumeration_borrow_mapping_by_index_const( - in_field_class, i, &label, &ranges); - range_count = - bt_field_class_signed_enumeration_mapping_ranges_get_range_count( - ranges); - /* - * Iterate over all the ranges to add them to copied field - * class. - */ - for (range_index = 0; range_index < range_count; range_index++) { - int64_t lower, upper; - bt_field_class_status status; - bt_field_class_signed_enumeration_mapping_ranges_get_range_by_index( - ranges, range_index, &lower, &upper); - - BT_LOGD("Copying range in enumeration field class: " - "label=%s, lower=%ld, upper=%ld", - label, lower, upper); - - /* Add the label and its range to the copy field class. */ - status = bt_field_class_signed_enumeration_map_range( - out_field_class, label, lower, upper); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Failed to add range to signed " - "enumeration."); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); - ret = -1; - goto error; - } - } - } - - BT_LOGD("Copied content of signed enumeration field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - -error: - return ret; -} - -static inline -int field_class_real_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - BT_LOGD("Copying content of real field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - - bt_field_class_real_set_is_single_precision(out_field_class, - bt_field_class_real_is_single_precision(in_field_class)); - - BT_LOGD("Copied content real field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - - return 0; -} - -static inline -int field_class_structure_copy( - struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class, - bt_field_class *out_field_class) -{ - uint64_t i, struct_member_count; - bt_field_class_status status; - int ret = 0; - - BT_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++) { - const bt_field_class_structure_member *member; - const char *member_name; - const bt_field_class *member_fc; - bt_field_class *out_member_field_class; - - member = bt_field_class_structure_borrow_member_by_index_const( - in_field_class, i); - member_fc = bt_field_class_structure_member_borrow_field_class_const( - member); - member_name = bt_field_class_structure_member_get_name(member); - BT_LOGD("Copying structure field class's field: " - "index=%" PRId64 ", " - "member-fc-addr=%p, field-name=\"%s\"", - i, member_fc, member_name); - - out_member_field_class = create_field_class_copy(md_maps, - member_fc); - if (!out_member_field_class) { - BT_LOGE("Cannot copy structure field class's field: " - "index=%" PRId64 ", " - "field-fc-addr=%p, field-name=\"%s\"", - i, member_fc, member_name); - ret = -1; - goto error; - } - ret = copy_field_class_content(md_maps, member_fc, - out_member_field_class); - if (ret) { - goto error; - } - - status = bt_field_class_structure_append_member(out_field_class, - member_name, out_member_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE("Cannot append structure field class's field: " - "index=%" PRId64 ", " - "field-fc-addr=%p, field-name=\"%s\"", - i, member_fc, member_name); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_field_class); - ret = -1; - goto error; - } - } - - BT_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p", - in_field_class, out_field_class); - -error: - return ret; -} - -static inline -int 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_field_class *out_tag_field_class; - uint64_t i, variant_option_count; - const bt_field_path *tag_fp; - const bt_field_class *tag_fc; - int ret = 0; - - BT_LOGD("Copying content of variant field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - - tag_fp = bt_field_class_variant_borrow_selector_field_path_const( - in_field_class); - if (tag_fp) { - tag_fc = resolve_field_path_to_field_class(tag_fp, - md_maps); - - out_tag_field_class = g_hash_table_lookup( - md_maps->field_class_map, tag_fc); - if (!out_tag_field_class) { - BT_LOGE_STR("Cannot find the tag field class."); - ret = -1; - goto error; - } - bt_field_class_variant_set_selector_field_class(out_field_class, - out_tag_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 *option_fc; - const char *option_name; - bt_field_class *out_option_field_class; - bt_field_class_status status; - const bt_field_class_variant_option *option; - - option = bt_field_class_variant_borrow_option_by_index_const( - in_field_class, i); - option_fc = bt_field_class_variant_option_borrow_field_class_const( - option); - option_name = bt_field_class_variant_option_get_name(option); - out_option_field_class = create_field_class_copy_internal( - md_maps, option_fc); - if (!out_option_field_class) { - BT_LOGE_STR("Cannot copy field class."); - ret = -1; - goto error; - } - ret = copy_field_class_content_internal(md_maps, option_fc, - out_option_field_class); - if (ret) { - BT_LOGE_STR("Error copying content of option variant " - "field class'"); - goto error; - } - - status = bt_field_class_variant_append_option( - out_field_class, option_name, - out_option_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Cannot append option to variant field class'"); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); - ret = -1; - goto error; - } - } - - BT_LOGD("Copied content of variant field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - -error: - return ret; -} - -static inline -int 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_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_LOGD("Copied content of static array field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - - return 0; -} - -static inline -int 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) -{ - const bt_field_class *len_fc; - const bt_field_path *len_fp; - bt_field_class_status status; - bt_field_class *out_len_field_class; - int ret = 0; - - BT_LOGD("Copying content of dynamic array field class: " - "in-fc-addr=%p, out-fc-addr=%p", - in_field_class, out_field_class); - - len_fp = bt_field_class_dynamic_array_borrow_length_field_path_const( - in_field_class); - - if (len_fp) { - BT_LOGD("Copying dynamic array length field class using " - "field path: in-len-fp=%p", len_fp); - len_fc = resolve_field_path_to_field_class( - len_fp, md_maps); - out_len_field_class = g_hash_table_lookup( - md_maps->field_class_map, len_fc); - if (!out_len_field_class) { - BT_LOGE_STR("Cannot find the output matching length" - "field class."); - ret = -1; - goto error; - } - - status = bt_field_class_dynamic_array_set_length_field_class( - out_field_class, out_len_field_class); - if (status != BT_FIELD_CLASS_STATUS_OK) { - BT_LOGE_STR("Cannot set dynamic array field class' " - "length field class."); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_len_field_class); - ret = -1; - goto error; - } - } - - BT_LOGD("Copied dynamic array field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - -error: - return ret; -} - -static inline -int 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_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_LOGD("Copied content of string field class: in-fc-addr=%p, " - "out-fc-addr=%p", in_field_class, out_field_class); - - return 0; -} - -static -bt_field_class *copy_field_class_array_element(struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_elem_fc) -{ - int ret; - bt_field_class *out_elem_fc = - create_field_class_copy_internal(md_maps, in_elem_fc); - if (!out_elem_fc) { - BT_LOGE("Error creating output elem field class " - "from input elem field class for static array: " - "in-fc-addr=%p", in_elem_fc); - goto error; - } - - ret = copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc); - if (ret) { - BT_LOGE("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 error; - } - -error: - return out_elem_fc; -} - -BT_HIDDEN -bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps *md_maps, - const bt_field_class *in_field_class) -{ - bt_field_class *out_field_class = NULL; - - BT_LOGD("Creating bare field class based on field class: in-fc-addr=%p", - in_field_class); - - switch(bt_field_class_get_type(in_field_class)) { - case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: - out_field_class = bt_field_class_unsigned_integer_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: - out_field_class = bt_field_class_signed_integer_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: - out_field_class = bt_field_class_unsigned_enumeration_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: - out_field_class = bt_field_class_signed_enumeration_create( - md_maps->output_trace_class); - break; - case BT_FIELD_CLASS_TYPE_REAL: - out_field_class = bt_field_class_real_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_static_array_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_static_array_create( - md_maps->output_trace_class, - out_elem_fc, array_len); - break; - } - case 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_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_dynamic_array_create( - md_maps->output_trace_class, - out_elem_fc); - break; - } - case BT_FIELD_CLASS_TYPE_VARIANT: - out_field_class = bt_field_class_variant_create( - md_maps->output_trace_class); - break; - default: - abort(); - } - - /* - * Add mapping from in_field_class to out_field_class. This simplifies - * the resolution of field paths in variant and dynamic array field - * classes. - */ - g_hash_table_insert(md_maps->field_class_map, - (gpointer) in_field_class, out_field_class); - -error: - if(out_field_class){ - BT_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_LOGE("Error creating output field class from input field " - "class: in-fc-addr=%p", in_field_class); - } - - return out_field_class; -} - -BT_HIDDEN -int 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) -{ - int ret = 0; - switch(bt_field_class_get_type(in_field_class)) { - case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: - ret = field_class_unsigned_integer_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: - ret = field_class_signed_integer_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: - ret = field_class_unsigned_enumeration_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION: - ret = field_class_signed_enumeration_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_REAL: - ret = field_class_real_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_STRING: - ret = field_class_string_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_STRUCTURE: - ret = field_class_structure_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: - ret = field_class_static_array_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: - ret = field_class_dynamic_array_copy(md_maps, - in_field_class, out_field_class); - break; - case BT_FIELD_CLASS_TYPE_VARIANT: - ret = field_class_variant_copy(md_maps, - in_field_class, out_field_class); - break; - default: - abort(); - } - - return ret; -} diff --git a/plugins/lttng-utils/trace-ir-metadata-field-class-copy.h b/plugins/lttng-utils/trace-ir-metadata-field-class-copy.h deleted file mode 100644 index 855e6cdc..00000000 --- a/plugins/lttng-utils/trace-ir-metadata-field-class-copy.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H - -/* - * Babeltrace - Trace IR metadata field class copy - * - * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2019 Francis Deslauriers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include "trace-ir-mapping.h" - -BT_HIDDEN -int 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_HIDDEN -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_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H */ diff --git a/plugins/lttng-utils/utils.c b/plugins/lttng-utils/utils.c deleted file mode 100644 index d9c5fa50..00000000 --- a/plugins/lttng-utils/utils.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Babeltrace - Debug info utilities - * - * Copyright (c) 2016 Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "utils.h" - -BT_HIDDEN -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; -} - -BT_HIDDEN -bt_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; - bt_bool match = BT_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) { - match = BT_FALSE; - goto end; - } - - if (bt_field_class_integer_get_field_value_range(ip_fc) != 64) { - 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 = BT_TRUE; - -end: - return match; -} diff --git a/plugins/lttng-utils/utils.h b/plugins/lttng-utils/utils.h deleted file mode 100644 index 5f65a470..00000000 --- a/plugins/lttng-utils/utils.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H -/* - * Babeltrace - Debug Info Utilities - * - * Copyright 2016 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include "trace-ir-mapping.h" - -/* - * Return the location of a path's file (the last element of the path). - * Returns the original path on error. - */ -BT_HIDDEN -const char *get_filename_from_path(const char *path); - -BT_HIDDEN -bt_bool is_event_common_ctx_dbg_info_compatible( - const bt_field_class *in_field_class, - const char *debug_info_field_class_name); - -#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H */ diff --git a/tests/plugins/Makefile.am b/tests/plugins/Makefile.am index e68d6671..29891787 100644 --- a/tests/plugins/Makefile.am +++ b/tests/plugins/Makefile.am @@ -16,7 +16,7 @@ endif # !ENABLE_BUILT_IN_PLUGINS if ENABLE_DEBUG_INFO test_dwarf_LDADD = \ - $(top_builddir)/plugins/lttng-utils/libdebug-info.la \ + $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \ $(top_builddir)/logging/libbabeltrace-logging.la \ $(top_builddir)/common/libbabeltrace-common.la \ $(ELFUTILS_LIBS) \ @@ -24,7 +24,7 @@ test_dwarf_LDADD = \ test_dwarf_SOURCES = test_dwarf.c test_bin_info_LDADD = \ - $(top_builddir)/plugins/lttng-utils/libdebug-info.la \ + $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \ $(top_builddir)/logging/libbabeltrace-logging.la \ $(top_builddir)/common/libbabeltrace-common.la \ $(ELFUTILS_LIBS) \ diff --git a/tests/plugins/test_bin_info.c b/tests/plugins/test_bin_info.c index f95cf0d7..b32f64fa 100644 --- a/tests/plugins/test_bin_info.c +++ b/tests/plugins/test_bin_info.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "tap/tap.h" #define NR_TESTS 36 diff --git a/tests/plugins/test_dwarf.c b/tests/plugins/test_dwarf.c index 8bae3d0b..59a892dd 100644 --- a/tests/plugins/test_dwarf.c +++ b/tests/plugins/test_dwarf.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "tap/tap.h" #define NR_TESTS 15