From: Philippe Proulx Date: Fri, 5 May 2017 17:12:29 +0000 (-0400) Subject: Rename debug_info.debug_info -> lttng-utils.debug-info X-Git-Tag: v2.0.0-pre1~315 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=456a4476cac0e5b5e5bec47a07243faee091eb72 Rename debug_info.debug_info -> lttng-utils.debug-info Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- diff --git a/configure.ac b/configure.ac index e937d25d..8890f4ab 100644 --- a/configure.ac +++ b/configure.ac @@ -507,7 +507,7 @@ AC_CONFIG_FILES([ plugins/utils/muxer/Makefile python-plugin-provider/Makefile plugins/libctfcopytrace/Makefile - plugins/debug-info/Makefile + plugins/lttng-utils/Makefile babeltrace.pc babeltrace-ctf.pc ]) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 9e4ff087..c6249c4d 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = libctfcopytrace ctf text utils writer if ENABLE_DEBUG_INFO -SUBDIRS += debug-info +SUBDIRS += lttng-utils endif noinst_HEADERS = plugins-common.h diff --git a/plugins/debug-info/Makefile.am b/plugins/debug-info/Makefile.am deleted file mode 100644 index 97a327bb..00000000 --- a/plugins/debug-info/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins \ - -I$(top_srcdir)/plugins/libctfcopytrace - -SUBDIRS = . - -plugindir = "$(PLUGINSDIR)" -plugin_LTLIBRARIES = libbabeltrace-plugin-debug-info.la - -noinst_HEADERS = \ - crc32.h \ - debug-info.h \ - dwarf.h \ - bin-info.h \ - utils.h \ - copy.h - -libbabeltrace_plugin_debug_info_la_SOURCES = \ - plugin.c debug-info.h debug-info.c bin-info.c dwarf.c crc32.c utils.c \ - copy.c - -libbabeltrace_plugin_debug_info_la_LDFLAGS = \ - -version-info $(BABELTRACE_LIBRARY_VERSION) -lelf -ldw - -libbabeltrace_plugin_debug_info_la_LIBADD = \ - $(top_builddir)/lib/libbabeltrace.la \ - $(top_builddir)/plugins/libctfcopytrace/libctfcopytrace.la diff --git a/plugins/debug-info/bin-info.c b/plugins/debug-info/bin-info.c deleted file mode 100644 index 170b351f..00000000 --- a/plugins/debug-info/bin-info.c +++ /dev/null @@ -1,1358 +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. - */ - -#include -#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 - -BT_HIDDEN -int bin_info_init(void) -{ - int ret = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) { - printf_debug("ELF library initialization failed: %s\n", - 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 = strdup(path); - } - - if (!bin->elf_path) { - goto error; - } - - if (debug_info_dir) { - bin->debug_info_dir = 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; - - 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); - - free(bin->debug_info_dir); - free(bin->elf_path); - free(bin->dwarf_path); - g_free(bin->build_id); - free(bin->dbg_link_filename); - - elf_end(bin->elf_file); - - close(bin->elf_fd); - close(bin->dwarf_fd); - - g_free(bin); -} - - -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; - } - - bin->build_id = malloc(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; - - /* - * 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 = 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 = 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 ? : 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 = malloc(build_id_file_len); - if (!build_id_file) { - goto error; - } - - 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); - - snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); - } - strcat(build_id_file, BUILD_ID_SUFFIX); - - 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 - * build ID 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 char *dbg_dir = NULL; - char *dir_name = NULL, *bin_dir = NULL, *path = NULL; - size_t max_path_len = 0; - - if (!bin || !bin->dbg_link_filename) { - goto error; - } - - dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR; - - dir_name = dirname(bin->elf_path); - if (!dir_name) { - goto error; - } - - /* bin_dir is just dir_name with a trailing slash */ - bin_dir = malloc(strlen(dir_name) + 2); - if (!bin_dir) { - goto error; - } - - strcpy(bin_dir, dir_name); - strcat(bin_dir, "/"); - - max_path_len = strlen(dbg_dir) + strlen(bin_dir) + - strlen(DEBUG_SUBDIR) + strlen(bin->dbg_link_filename) - + 1; - path = malloc(max_path_len); - if (!path) { - goto error; - } - - /* First look in the executable's dir */ - strcpy(path, bin_dir); - strcat(path, bin->dbg_link_filename); - - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - - /* If not found, look in .debug subdir */ - strcpy(path, bin_dir); - strcat(path, DEBUG_SUBDIR); - strcat(path, bin->dbg_link_filename); - - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - - /* Lastly, look under the global debug directory */ - strcpy(path, dbg_dir); - strcat(path, bin_dir); - strcat(path, bin->dbg_link_filename); - - if (is_valid_debug_file(path, bin->dbg_link_crc)) { - goto found; - } - -error: - ret = -1; -end: - free(path); - free(bin_dir); - - 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; -} - -/** - * 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; - printf_verbose("Failed to open %s\n", bin->elf_path); - goto error; - } - - elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); - if (!elf_file) { - printf_debug("elf_begin failed: %s\n", elf_errmsg(-1)); - goto error; - } - - if (elf_kind(elf_file) != ELF_K_ELF) { - printf_verbose("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; -} - -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) -{ - int ret; - uint64_t offset; - char *_result = NULL; - char offset_str[ADDR_STR_LEN]; - - if (!base_str || !result) { - goto error; - } - - offset = high_addr - low_addr; - - _result = malloc(strlen(base_str) + ADDR_STR_LEN); - if (!_result) { - goto error; - } - - ret = snprintf(offset_str, ADDR_STR_LEN, "+%#0" PRIx64, offset); - if (ret < 0) { - goto error; - } - strcpy(_result, base_str); - strcat(_result, offset_str); - *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; - } - - /* 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) { - printf_verbose("Failed to set bin dwarf info, falling back to ELF lookup.\n"); - /* 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); - printf_verbose("Failed to lookup function name (elf), error %i\n", ret); - } else { - ret = bin_info_lookup_dwarf_function_name(bin, addr, &_func_name); - printf_verbose("Failed to lookup function name (dwarf), error %i\n", 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) -{ - int ret = 0; - char *_bin_loc = NULL; - - if (!bin || !bin_loc) { - goto error; - } - - if (bin->is_pic) { - addr -= bin->low_addr; - ret = asprintf(&_bin_loc, "+%#0" PRIx64, addr); - } else { - ret = asprintf(&_bin_loc, "@%#0" PRIx64, addr); - } - - if (ret == -1 || !_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 { - int tag; - - ret = bt_dwarf_die_get_tag(die, &tag); - if (ret) { - goto error; - } - - if (tag == DW_TAG_inlined_subroutine) { - ret = bt_dwarf_die_contains_addr(die, addr, &_contains); - if (ret) { - goto error; - } - - if (_contains) { - goto end; - } - } - } 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 = 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; - } - - /* 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/debug-info/bin-info.h b/plugins/debug-info/bin-info.h deleted file mode 100644 index 05d0d797..00000000 --- a/plugins/debug-info/bin-info.h +++ /dev/null @@ -1,233 +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. */ - char *elf_path; - char *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. */ - char *dbg_link_filename; - uint32_t dbg_link_crc; - /* FDs to ELF and DWARF files. */ - int elf_fd; - int dwarf_fd; - /* Configuration. */ - char *debug_info_dir; - /* Denotes whether the executable is position independent code. */ - bool is_pic: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; - char *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/debug-info/copy.c b/plugins/debug-info/copy.c deleted file mode 100644 index 2689a703..00000000 --- a/plugins/debug-info/copy.c +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * copy.c - * - * Babeltrace Copy Trace Structure - * - * Copyright 2017 Julien Desfossez - * - * Author: Julien Desfossez - * - * 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 -#include -#include -#include -#include - -#include -#include "debug-info.h" - -static -struct bt_ctf_field *get_payload_field(FILE *err, - struct bt_ctf_event *event, const char *field_name) -{ - struct bt_ctf_field *field = NULL, *sec = NULL; - struct bt_ctf_field_type *sec_type = NULL; - - sec = bt_ctf_event_get_payload(event, NULL); - if (!sec) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - sec_type = bt_ctf_field_get_type(sec); - if (!sec_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - if (bt_ctf_field_type_get_type_id(sec_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - field = bt_ctf_field_structure_get_field(sec, field_name); - -end: - bt_put(sec_type); - bt_put(sec); - return field; -} - -static -struct bt_ctf_field *get_stream_event_context_field(FILE *err, - struct bt_ctf_event *event, const char *field_name) -{ - struct bt_ctf_field *field = NULL, *sec = NULL; - struct bt_ctf_field_type *sec_type = NULL; - - sec = bt_ctf_event_get_stream_event_context(event); - if (!sec) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - sec_type = bt_ctf_field_get_type(sec); - if (!sec_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - if (bt_ctf_field_type_get_type_id(sec_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - field = bt_ctf_field_structure_get_field(sec, field_name); - -end: - bt_put(sec_type); - bt_put(sec); - return field; -} - -BT_HIDDEN -int get_stream_event_context_unsigned_int_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint64_t *value) -{ - int ret; - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - - field = get_stream_event_context_field(err, event, field_name); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_unsigned_integer_get_value(field, value); - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -BT_HIDDEN -int get_stream_event_context_int_field_value(FILE *err, struct bt_ctf_event *event, - const char *field_name, int64_t *value) -{ - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - int ret; - - field = get_stream_event_context_field(err, event, field_name); - if (!field) { - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_signed_integer_get_value(field, value); - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -BT_HIDDEN -int get_payload_unsigned_int_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint64_t *value) -{ - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - int ret; - - field = get_payload_field(err, event, field_name); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_unsigned_integer_get_value(field, value); - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -BT_HIDDEN -int get_payload_int_field_value(FILE *err, struct bt_ctf_event *event, - const char *field_name, int64_t *value) -{ - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - int ret; - - field = get_payload_field(err, event, field_name); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_signed_integer_get_value(field, value); - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -BT_HIDDEN -int get_payload_string_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - const char **value) -{ - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - int ret; - - field = get_payload_field(err, event, field_name); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_STRING) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - *value = bt_ctf_field_string_get_value(field); - if (!*value) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = 0; - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -BT_HIDDEN -int get_payload_build_id_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint8_t **build_id, uint64_t *build_id_len) -{ - struct bt_ctf_field *field = NULL, *seq_len = NULL; - struct bt_ctf_field_type *field_type = NULL; - struct bt_ctf_field *seq_field = NULL; - uint64_t i; - int ret; - - *build_id = NULL; - - field = get_payload_field(err, event, field_name); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field_type = bt_ctf_field_get_type(field); - if (!field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(field_type); - - seq_len = bt_ctf_field_sequence_get_length(field); - if (!seq_len) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_unsigned_integer_get_value(seq_len, build_id_len); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(seq_len); - - *build_id = g_new0(uint8_t, *build_id_len); - if (!*build_id) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - for (i = 0; i < *build_id_len; i++) { - uint64_t tmp; - - seq_field = bt_ctf_field_sequence_get_field(field, i); - if (!seq_field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_unsigned_integer_get_value(seq_field, &tmp); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(seq_field); - (*build_id)[i] = (uint8_t) tmp; - } - ret = 0; - goto end; - -error: - g_free(*build_id); - ret = -1; -end: - bt_put(field_type); - bt_put(field); - return ret; -} - -static -struct debug_info *lookup_trace_debug_info(struct debug_info_iterator *debug_it, - struct bt_ctf_trace *writer_trace) -{ - return (struct debug_info *) g_hash_table_lookup( - debug_it->trace_debug_map, - (gpointer) writer_trace); -} - -static -struct debug_info *insert_new_debug_info(struct debug_info_iterator *debug_it, - struct bt_ctf_trace *writer_trace) -{ - struct debug_info *debug_info = NULL; - struct bt_value *field = NULL; - const char *str_value; - enum bt_value_status ret; - - field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, - "domain"); - /* No domain field, no debug info */ - if (!field) { - goto end; - } - ret = bt_value_string_get(field, &str_value); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - /* Domain not ust, no debug info */ - if (strcmp(str_value, "ust") != 0) { - goto end; - } - BT_PUT(field); - - /* No tracer_name, no debug info */ - field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, - "tracer_name"); - /* No tracer_name, no debug info */ - if (!field) { - goto end; - } - ret = bt_value_string_get(field, &str_value); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - /* Tracer_name not lttng-ust, no debug info */ - if (strcmp(str_value, "lttng-ust") != 0) { - goto end; - } - BT_PUT(field); - - debug_info = debug_info_create(debug_it->debug_info_component); - if (!debug_info) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - - g_hash_table_insert(debug_it->trace_debug_map, (gpointer) writer_trace, - debug_info); - -end: - bt_put(field); - return debug_info; -} - -static -struct debug_info *get_trace_debug_info(struct debug_info_iterator *debug_it, - struct bt_ctf_trace *writer_trace) -{ - struct debug_info *debug_info; - - debug_info = lookup_trace_debug_info(debug_it, writer_trace); - if (debug_info) { - goto end; - } - - debug_info = insert_new_debug_info(debug_it, writer_trace); - -end: - return debug_info; -} - -static -struct bt_ctf_trace *lookup_trace(struct debug_info_iterator *debug_it, - struct bt_ctf_trace *trace) -{ - return (struct bt_ctf_trace *) g_hash_table_lookup( - debug_it->trace_map, - (gpointer) trace); -} - -static -struct bt_ctf_trace *insert_new_trace(struct debug_info_iterator *debug_it, - struct bt_ctf_trace *trace) { - struct bt_ctf_trace *writer_trace = NULL; - int ret; - - writer_trace = bt_ctf_trace_create(); - if (!writer_trace) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - g_hash_table_insert(debug_it->trace_map, (gpointer) trace, writer_trace); - - ret = ctf_copy_trace(debug_it->err, trace, writer_trace); - if (ret != BT_COMPONENT_STATUS_OK) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - goto end; - -error: - BT_PUT(writer_trace); -end: - return writer_trace; -} - -static -struct bt_ctf_packet *lookup_packet(struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet) -{ - return (struct bt_ctf_packet *) g_hash_table_lookup( - debug_it->packet_map, - (gpointer) packet); -} - -static -struct bt_ctf_packet *insert_new_packet(struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet, - struct bt_ctf_stream *writer_stream) -{ - struct bt_ctf_packet *writer_packet; - - writer_packet = bt_ctf_packet_create(writer_stream); - if (!writer_packet) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto end; - } - g_hash_table_insert(debug_it->packet_map, (gpointer) packet, writer_packet); - -end: - return writer_packet; -} - -static -int add_debug_info_fields(FILE *err, - struct bt_ctf_field_type *writer_event_context_type, - struct debug_info_component *component) -{ - struct bt_ctf_field_type *ip_field = NULL, *debug_field_type = NULL, - *bin_field_type = NULL, *func_field_type = NULL, - *src_field_type = NULL; - int ret = 0; - - ip_field = bt_ctf_field_type_structure_get_field_type_by_name( - writer_event_context_type, "_ip"); - /* No ip field, so no debug info. */ - if (!ip_field) { - goto end; - } - BT_PUT(ip_field); - - debug_field_type = bt_ctf_field_type_structure_get_field_type_by_name( - writer_event_context_type, - component->arg_debug_info_field_name); - /* Already existing debug_info field, no need to add it. */ - if (debug_field_type) { - goto end; - } - - debug_field_type = bt_ctf_field_type_structure_create(); - if (!debug_field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - bin_field_type = bt_ctf_field_type_string_create(); - if (!bin_field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - func_field_type = bt_ctf_field_type_string_create(); - if (!func_field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - src_field_type = bt_ctf_field_type_string_create(); - if (!src_field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = bt_ctf_field_type_structure_add_field(debug_field_type, - bin_field_type, "bin"); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = bt_ctf_field_type_structure_add_field(debug_field_type, - func_field_type, "func"); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = bt_ctf_field_type_structure_add_field(debug_field_type, - src_field_type, "src"); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, - debug_field_type, component->arg_debug_info_field_name); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = 0; - goto end; - -error: - BT_PUT(debug_field_type); - ret = -1; -end: - bt_put(src_field_type); - bt_put(func_field_type); - bt_put(bin_field_type); - bt_put(debug_field_type); - return ret; -} - -static -int create_debug_info_event_context_type(FILE *err, - struct bt_ctf_field_type *event_context_type, - struct bt_ctf_field_type *writer_event_context_type, - struct debug_info_component *component) -{ - int ret, nr_fields, i; - - nr_fields = bt_ctf_field_type_structure_get_field_count(event_context_type); - for (i = 0; i < nr_fields; i++) { - struct bt_ctf_field_type *field_type = NULL; - const char *field_name; - - if (bt_ctf_field_type_structure_get_field(event_context_type, - &field_name, &field_type, i) < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, - field_type, field_name); - BT_PUT(field_type); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - } - - ret = add_debug_info_fields(err, writer_event_context_type, - component); - goto end; - -error: - ret = -1; -end: - return ret; -} - -static -struct bt_ctf_stream_class *copy_stream_class_debug_info(FILE *err, - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_trace *writer_trace, - struct debug_info_component *component) -{ - struct bt_ctf_field_type *type = NULL; - struct bt_ctf_stream_class *writer_stream_class = NULL; - struct bt_ctf_field_type *writer_event_context_type = NULL; - int ret_int; - const char *name = bt_ctf_stream_class_get_name(stream_class); - - if (strlen(name) == 0) { - name = NULL; - } - - writer_stream_class = bt_ctf_stream_class_create(name); - if (!writer_stream_class) { - fprintf(err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - type = bt_ctf_stream_class_get_packet_context_type(stream_class); - if (!type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret_int = bt_ctf_stream_class_set_packet_context_type( - writer_stream_class, type); - if (ret_int < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - BT_PUT(type); - - type = bt_ctf_stream_class_get_event_header_type(stream_class); - if (!type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret_int = bt_ctf_stream_class_set_event_header_type( - writer_stream_class, type); - if (ret_int < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - BT_PUT(type); - - type = bt_ctf_stream_class_get_event_context_type(stream_class); - if (type) { - writer_event_context_type = bt_ctf_field_type_structure_create(); - if (!writer_event_context_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - ret_int = create_debug_info_event_context_type(err, type, - writer_event_context_type, component); - if (ret_int) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - BT_PUT(type); - - ret_int = bt_ctf_stream_class_set_event_context_type( - writer_stream_class, writer_event_context_type); - if (ret_int < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - BT_PUT(writer_event_context_type); - } - - goto end; - -error: - BT_PUT(writer_stream_class); -end: - bt_put(writer_event_context_type); - bt_put(type); - return writer_stream_class; -} - -/* - * Add the original clock classes to the new trace, we do not need to copy - * them, and if we did, we would have to manually inspect the stream class - * to update the integers mapping to a clock. - */ -static -int add_clock_classes(FILE *err, struct bt_ctf_trace *writer_trace, - struct bt_ctf_stream_class *writer_stream_class, - struct bt_ctf_trace *trace) -{ - int ret, clock_class_count, i; - - clock_class_count = bt_ctf_trace_get_clock_class_count(trace); - - for (i = 0; i < clock_class_count; i++) { - struct bt_ctf_clock_class *clock_class = - bt_ctf_trace_get_clock_class_by_index(trace, i); - - if (!clock_class) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = bt_ctf_trace_add_clock_class(writer_trace, clock_class); - BT_PUT(clock_class); - if (ret != 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - } - - ret = 0; - goto end; - -error: - ret = -1; -end: - return ret; - -} - -static -struct bt_ctf_stream_class *insert_new_stream_class( - struct debug_info_iterator *debug_it, - struct bt_ctf_stream_class *stream_class) -{ - struct bt_ctf_stream_class *writer_stream_class = NULL; - struct bt_ctf_trace *trace, *writer_trace = NULL; - enum bt_component_status ret; - int int_ret; - - trace = bt_ctf_stream_class_get_trace(stream_class); - if (!trace) { - fprintf(debug_it->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - writer_trace = lookup_trace(debug_it, trace); - if (!writer_trace) { - writer_trace = insert_new_trace(debug_it, trace); - if (!writer_trace) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = BT_COMPONENT_STATUS_ERROR; - goto error; - } - } - bt_get(writer_trace); - - writer_stream_class = copy_stream_class_debug_info(debug_it->err, stream_class, - writer_trace, debug_it->debug_info_component); - if (!writer_stream_class) { - fprintf(debug_it->err, "[error] Failed to copy stream class\n"); - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - int_ret = bt_ctf_trace_add_stream_class(writer_trace, writer_stream_class); - if (int_ret) { - fprintf(debug_it->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = add_clock_classes(debug_it->err, writer_trace, - writer_stream_class, trace); - if (ret != BT_COMPONENT_STATUS_OK) { - fprintf(debug_it->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - BT_PUT(writer_trace); - BT_PUT(trace); - - g_hash_table_insert(debug_it->stream_class_map, - (gpointer) stream_class, writer_stream_class); - - goto end; - -error: - BT_PUT(writer_stream_class); -end: - bt_put(trace); - bt_put(writer_trace); - return writer_stream_class; -} - -static -struct bt_ctf_stream *insert_new_stream( - struct debug_info_iterator *debug_it, - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_stream *stream) -{ - struct bt_ctf_stream *writer_stream = NULL; - struct bt_ctf_stream_class *writer_stream_class = NULL; - - writer_stream_class = g_hash_table_lookup( - debug_it->stream_class_map, - (gpointer) stream_class); - - if (!writer_stream_class) { - writer_stream_class = insert_new_stream_class(debug_it, - stream_class); - if (!writer_stream_class) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - } - bt_get(writer_stream_class); - - writer_stream = bt_ctf_stream_create(writer_stream_class, - bt_ctf_stream_get_name(stream)); - if (!writer_stream) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - g_hash_table_insert(debug_it->stream_map, (gpointer) stream, - writer_stream); - - goto end; - -error: - BT_PUT(writer_stream); -end: - bt_put(writer_stream_class); - return writer_stream; -} - -static -struct bt_ctf_stream *lookup_stream(struct debug_info_iterator *debug_it, - struct bt_ctf_stream *stream) -{ - return (struct bt_ctf_stream *) g_hash_table_lookup( - debug_it->stream_map, - (gpointer) stream); -} - -static -struct bt_ctf_event_class *get_event_class(struct debug_info_iterator *debug_it, - struct bt_ctf_stream_class *writer_stream_class, - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_stream_class_get_event_class_by_id(writer_stream_class, - bt_ctf_event_class_get_id(event_class)); -} - -static -struct bt_ctf_stream *get_writer_stream( - struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet, struct bt_ctf_stream *stream) -{ - struct bt_ctf_stream_class *stream_class = NULL; - struct bt_ctf_stream *writer_stream = NULL; - - stream_class = bt_ctf_stream_get_class(stream); - if (!stream_class) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - writer_stream = lookup_stream(debug_it, stream); - if (!writer_stream) { - writer_stream = insert_new_stream(debug_it, stream_class, stream); - } - bt_get(writer_stream); - - goto end; - -error: - BT_PUT(writer_stream); -end: - bt_put(stream_class); - return writer_stream; -} - -BT_HIDDEN -struct bt_ctf_packet *debug_info_new_packet( - struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet) -{ - struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; - struct bt_ctf_field *writer_packet_context = NULL; - struct bt_ctf_packet *writer_packet = NULL; - int int_ret; - - stream = bt_ctf_packet_get_stream(packet); - if (!stream) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - writer_stream = get_writer_stream(debug_it, packet, stream); - if (!writer_stream) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - /* - * If a packet was already opened, close it and remove it from - * the HT. - */ - writer_packet = lookup_packet(debug_it, packet); - if (writer_packet) { - g_hash_table_remove(debug_it->packet_map, packet); - BT_PUT(writer_packet); - } - - writer_packet = insert_new_packet(debug_it, packet, writer_stream); - if (!writer_packet) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - bt_get(writer_packet); - - writer_packet_context = ctf_copy_packet_context(debug_it->err, packet, - writer_stream); - if (!writer_packet_context) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - int_ret = bt_ctf_packet_set_context(writer_packet, writer_packet_context); - if (int_ret) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - goto end; - -error: - -end: - bt_put(writer_packet_context); - bt_put(writer_stream); - bt_put(stream); - return writer_packet; -} - -BT_HIDDEN -struct bt_ctf_packet *debug_info_close_packet( - struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet) -{ - struct bt_ctf_packet *writer_packet = NULL; - - writer_packet = lookup_packet(debug_it, packet); - if (!writer_packet) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto end; - } - g_hash_table_remove(debug_it->packet_map, packet); - -end: - return writer_packet; -} - -BT_HIDDEN -struct bt_ctf_stream *debug_info_stream_end(struct debug_info_iterator *debug_it, - struct bt_ctf_stream *stream) -{ - struct bt_ctf_stream *writer_stream; - - writer_stream = lookup_stream(debug_it, stream); - if (!writer_stream) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto end; - } - g_hash_table_remove(debug_it->stream_map, stream); - -end: - return writer_stream; -} - -static -struct debug_info_source *lookup_debug_info(FILE *err, - struct bt_ctf_event *event, - struct debug_info *debug_info) -{ - int64_t vpid; - uint64_t ip; - struct debug_info_source *dbg_info_src = NULL; - int ret; - - ret = get_stream_event_context_int_field_value(err, event, - "_vpid", &vpid); - if (ret) { - goto end; - } - - ret = get_stream_event_context_unsigned_int_field_value(err, event, - "_ip", &ip); - if (ret) { - goto end; - } - - /* Get debug info for this context. */ - dbg_info_src = debug_info_query(debug_info, vpid, ip); - -end: - return dbg_info_src; -} - -static -int set_debug_info_field(FILE *err, struct bt_ctf_field *debug_field, - struct debug_info_source *dbg_info_src, - struct debug_info_component *component) -{ - int i, nr_fields, ret; - struct bt_ctf_field_type *debug_field_type = NULL; - struct bt_ctf_field *field = NULL; - struct bt_ctf_field_type *field_type = NULL; - - debug_field_type = bt_ctf_field_get_type(debug_field); - if (!debug_field_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - nr_fields = bt_ctf_field_type_structure_get_field_count(debug_field_type); - for (i = 0; i < nr_fields; i++) { - const char *field_name; - - if (bt_ctf_field_type_structure_get_field(debug_field_type, - &field_name, &field_type, i) < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(field_type); - - field = bt_ctf_field_structure_get_field_by_index(debug_field, i); - if (!strcmp(field_name, "bin")) { - if (dbg_info_src && dbg_info_src->bin_path) { - GString *tmp = g_string_new(NULL); - - if (component->arg_full_path) { - g_string_printf(tmp, "%s%s", - dbg_info_src->bin_path, - dbg_info_src->bin_loc); - } else { - g_string_printf(tmp, "%s%s", - dbg_info_src->short_bin_path, - dbg_info_src->bin_loc); - } - ret = bt_ctf_field_string_set_value(field, tmp->str); - g_string_free(tmp, true); - } else { - ret = bt_ctf_field_string_set_value(field, ""); - } - } else if (!strcmp(field_name, "func")) { - if (dbg_info_src && dbg_info_src->func) { - ret = bt_ctf_field_string_set_value(field, - dbg_info_src->func); - } else { - ret = bt_ctf_field_string_set_value(field, ""); - } - } else if (!strcmp(field_name, "src")) { - if (dbg_info_src && dbg_info_src->src_path) { - GString *tmp = g_string_new(NULL); - - if (component->arg_full_path) { - g_string_printf(tmp, "%s:%" PRId64, - dbg_info_src->src_path, - dbg_info_src->line_no); - } else { - g_string_printf(tmp, "%s:%" PRId64, - dbg_info_src->short_src_path, - dbg_info_src->line_no); - } - ret = bt_ctf_field_string_set_value(field, tmp->str); - g_string_free(tmp, true); - } else { - ret = bt_ctf_field_string_set_value(field, ""); - } - } - BT_PUT(field); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - } - ret = 0; - goto end; - -error: - ret = -1; -end: - bt_put(field_type); - bt_put(field); - bt_put(debug_field_type); - return ret; -} - -static -int copy_set_debug_info_stream_event_context(FILE *err, - struct bt_ctf_field *event_context, - struct bt_ctf_event *event, - struct bt_ctf_event *writer_event, - struct debug_info *debug_info, - struct debug_info_component *component) -{ - struct bt_ctf_field_type *writer_event_context_type = NULL; - struct bt_ctf_field *writer_event_context = NULL; - struct bt_ctf_field *field = NULL, *copy_field = NULL, *debug_field = NULL; - struct bt_ctf_field_type *field_type = NULL; - struct debug_info_source *dbg_info_src; - int ret, nr_fields, i; - - writer_event_context = bt_ctf_event_get_stream_event_context(writer_event); - if (!writer_event_context) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto error; - } - - writer_event_context_type = bt_ctf_field_get_type(writer_event_context); - if (!writer_event_context_type) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - /* - * If it is not a structure, we did not modify it to add the debug info - * fields, so just assign it as is. - */ - if (bt_ctf_field_type_get_type_id(writer_event_context_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { - ret = bt_ctf_event_set_event_context(writer_event, event_context); - goto end; - } - - dbg_info_src = lookup_debug_info(err, event, debug_info); - - nr_fields = bt_ctf_field_type_structure_get_field_count(writer_event_context_type); - for (i = 0; i < nr_fields; i++) { - const char *field_name; - - if (bt_ctf_field_type_structure_get_field(writer_event_context_type, - &field_name, &field_type, i) < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field = bt_ctf_field_structure_get_field_by_index(event_context, i); - /* - * The debug_info field, only exists in the writer event or - * if it was set by a earlier pass of the debug_info plugin. - * - * FIXME: are we replacing an exisiting debug_info struct here ?? - */ - if (!strcmp(field_name, component->arg_debug_info_field_name) && - !field) { - debug_field = bt_ctf_field_structure_get_field_by_index( - writer_event_context, i); - if (!debug_field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - ret = set_debug_info_field(err, debug_field, - dbg_info_src, component); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(debug_field); - } else { - copy_field = bt_ctf_field_copy(field); - if (!copy_field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = bt_ctf_field_structure_set_field(writer_event_context, - field_name, copy_field); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(copy_field); - } - BT_PUT(field_type); - BT_PUT(field); - } - - ret = 0; - goto end; - -error: - ret = -1; -end: - bt_put(writer_event_context_type); - bt_put(writer_event_context); - bt_put(field); - bt_put(copy_field); - bt_put(debug_field); - bt_put(field_type); - return ret; -} - -static -struct bt_ctf_clock_class *stream_class_get_clock_class(FILE *err, - struct bt_ctf_stream_class *stream_class) -{ - struct bt_ctf_trace *trace = NULL; - struct bt_ctf_clock_class *clock_class = NULL; - - trace = bt_ctf_stream_class_get_trace(stream_class); - if (!trace) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto end; - } - - /* FIXME multi-clock? */ - clock_class = bt_ctf_trace_get_clock_class_by_index(trace, 0); - - bt_put(trace); - -end: - return clock_class; -} - -static -struct bt_ctf_clock_class *event_get_clock_class(FILE *err, struct bt_ctf_event *event) -{ - struct bt_ctf_event_class *event_class = NULL; - struct bt_ctf_stream_class *stream_class = NULL; - struct bt_ctf_clock_class *clock_class = NULL; - - event_class = bt_ctf_event_get_class(event); - if (!event_class) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - stream_class = bt_ctf_event_class_get_stream_class(event_class); - if (!stream_class) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - clock_class = stream_class_get_clock_class(err, stream_class); - goto end; - -error: - BT_PUT(clock_class); -end: - bt_put(stream_class); - bt_put(event_class); - return clock_class; -} - -static -int set_event_clock_value(FILE *err, struct bt_ctf_event *event, - struct bt_ctf_event *writer_event) -{ - struct bt_ctf_clock_class *clock_class = NULL; - struct bt_ctf_clock_value *clock_value = NULL; - int ret; - - clock_class = event_get_clock_class(err, event); - if (!clock_class) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - clock_value = bt_ctf_event_get_clock_value(event, clock_class); - if (!clock_value) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - /* - * We share the same clocks, so we can assign the clock value to the - * writer event. - */ - ret = bt_ctf_event_set_clock_value(writer_event, clock_value); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = 0; - goto end; - -error: - ret = -1; -end: - bt_put(clock_class); - bt_put(clock_value); - return ret; -} - -static -struct bt_ctf_event *debug_info_copy_event(FILE *err, struct bt_ctf_event *event, - struct bt_ctf_event_class *writer_event_class, - struct debug_info *debug_info, - struct debug_info_component *component) -{ - struct bt_ctf_event *writer_event = NULL; - struct bt_ctf_field *field = NULL, *copy_field = NULL; - int ret; - - writer_event = bt_ctf_event_create(writer_event_class); - if (!writer_event) { - fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = set_event_clock_value(err, event, writer_event); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - field = bt_ctf_event_get_header(event); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - ret = ctf_copy_event_header(err, event, writer_event_class, - writer_event, field); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(field); - - /* Optional field, so it can fail silently. */ - field = bt_ctf_event_get_stream_event_context(event); - if (field) { - ret = copy_set_debug_info_stream_event_context(err, - field, event, writer_event, debug_info, - component); - if (ret < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(field); - } - - /* Optional field, so it can fail silently. */ - field = bt_ctf_event_get_event_context(event); - copy_field = bt_ctf_field_copy(field); - if (copy_field) { - ret = bt_ctf_event_set_event_context(writer_event, copy_field); - if (ret < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(copy_field); - } - BT_PUT(field); - - field = bt_ctf_event_get_event_payload(event); - if (!field) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - copy_field = bt_ctf_field_copy(field); - if (copy_field) { - ret = bt_ctf_event_set_event_payload(writer_event, copy_field); - if (ret < 0) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(copy_field); - } - BT_PUT(field); - - goto end; - -error: - BT_PUT(writer_event); -end: - bt_put(copy_field); - bt_put(field); - return writer_event; -} - -BT_HIDDEN -struct bt_ctf_event *debug_info_output_event( - struct debug_info_iterator *debug_it, - struct bt_ctf_event *event) -{ - struct bt_ctf_event_class *event_class = NULL, *writer_event_class = NULL; - struct bt_ctf_stream_class *stream_class = NULL, *writer_stream_class = NULL; - struct bt_ctf_event *writer_event = NULL; - struct bt_ctf_packet *packet = NULL, *writer_packet = NULL; - struct bt_ctf_trace *writer_trace = NULL; - struct debug_info *debug_info; - const char *event_name; - int int_ret; - - event_class = bt_ctf_event_get_class(event); - if (!event_class) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - event_name = bt_ctf_event_class_get_name(event_class); - if (!event_name) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - stream_class = bt_ctf_event_class_get_stream_class(event_class); - if (!stream_class) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_stream_class = g_hash_table_lookup( - debug_it->stream_class_map, - (gpointer) stream_class); - if (!writer_stream_class || !bt_get(writer_stream_class)) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_event_class = get_event_class(debug_it, - writer_stream_class, event_class); - if (!writer_event_class) { - writer_event_class = ctf_copy_event_class(debug_it->err, - event_class); - if (!writer_event_class) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - int_ret = bt_ctf_stream_class_add_event_class( - writer_stream_class, writer_event_class); - if (int_ret) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - } - - writer_trace = bt_ctf_stream_class_get_trace(writer_stream_class); - if (!writer_trace) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - debug_info = get_trace_debug_info(debug_it, writer_trace); - if (debug_info) { - debug_info_handle_event(debug_it->err, event, debug_info); - } - - writer_event = debug_info_copy_event(debug_it->err, event, - writer_event_class, debug_info, - debug_it->debug_info_component); - if (!writer_event) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - fprintf(debug_it->err, "[error] Failed to copy event %s\n", - bt_ctf_event_class_get_name(writer_event_class)); - goto error; - } - - packet = bt_ctf_event_get_packet(event); - if (!packet) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_packet = lookup_packet(debug_it, packet); - if (!writer_packet) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - bt_get(writer_packet); - - int_ret = bt_ctf_event_set_packet(writer_event, writer_packet); - if (int_ret < 0) { - fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - fprintf(debug_it->err, "[error] Failed to append event %s\n", - bt_ctf_event_class_get_name(writer_event_class)); - goto error; - } - - /* Keep the reference on the writer event */ - goto end; - -error: - BT_PUT(writer_event); - -end: - bt_put(writer_trace); - bt_put(writer_packet); - bt_put(packet); - bt_put(writer_event_class); - bt_put(writer_stream_class); - bt_put(stream_class); - bt_put(event_class); - return writer_event; -} diff --git a/plugins/debug-info/copy.h b/plugins/debug-info/copy.h deleted file mode 100644 index e1441dde..00000000 --- a/plugins/debug-info/copy.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_TRIMMER_COPY_H -#define BABELTRACE_PLUGIN_TRIMMER_COPY_H - -/* - * BabelTrace - Copy Trace Structure - * - * Copyright 2017 Julien Desfossez - * - * Author: Julien Desfossez - * - * 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 - -BT_HIDDEN -struct bt_ctf_event *debug_info_output_event(struct debug_info_iterator *debug_it, - struct bt_ctf_event *event); -BT_HIDDEN -struct bt_ctf_packet *debug_info_new_packet(struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet); -BT_HIDDEN -struct bt_ctf_packet *debug_info_close_packet(struct debug_info_iterator *debug_it, - struct bt_ctf_packet *packet); -BT_HIDDEN -struct bt_ctf_stream *debug_info_stream_end(struct debug_info_iterator *debug_it, - struct bt_ctf_stream *stream); - -BT_HIDDEN -int get_stream_event_context_unsigned_int_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint64_t *value); -BT_HIDDEN -int get_stream_event_context_int_field_value(FILE *err, struct bt_ctf_event *event, - const char *field_name, int64_t *value); -BT_HIDDEN -int get_payload_unsigned_int_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint64_t *value); -BT_HIDDEN -int get_payload_int_field_value(FILE *err, struct bt_ctf_event *event, - const char *field_name, int64_t *value); -BT_HIDDEN -int get_payload_string_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - const char **value); -BT_HIDDEN -int get_payload_build_id_field_value(FILE *err, - struct bt_ctf_event *event, const char *field_name, - uint8_t **build_id, uint64_t *build_id_len); - -#endif /* BABELTRACE_PLUGIN_TRIMMER_COPY_H */ diff --git a/plugins/debug-info/crc32.c b/plugins/debug-info/crc32.c deleted file mode 100644 index e68c0434..00000000 --- a/plugins/debug-info/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/debug-info/crc32.h b/plugins/debug-info/crc32.h deleted file mode 100644 index 4a229d63..00000000 --- a/plugins/debug-info/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/debug-info/debug-info.c b/plugins/debug-info/debug-info.c deleted file mode 100644 index bc8fa6dd..00000000 --- a/plugins/debug-info/debug-info.c +++ /dev/null @@ -1,761 +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 - * - * 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 "debug-info.h" -#include "bin-info.h" -#include "utils.h" -#include "copy.h" - -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; - - /* - * Hash table of VPIDs (pointer to int64_t) to - * (struct ctf_proc_debug_infos*); 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; - } - - free(debug_info_src->func); - free(debug_info_src->src_path); - free(debug_info_src->bin_path); - 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); - printf_verbose("Failed to lookup source location (err: %i)\n", ret); - } - - if (src_loc) { - debug_info_src->line_no = src_loc->line_no; - - if (src_loc->filename) { - debug_info_src->src_path = 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 = 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 -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) -{ - 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; - } - -end: - return debug_info; -error: - g_free(debug_info); - return NULL; -} - -BT_HIDDEN -void debug_info_destroy(struct debug_info *debug_info) -{ - 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); - } - - g_free(debug_info); -end: - return; -} - -static -void handle_statedump_build_id_event(FILE *err, struct debug_info *debug_info, - struct bt_ctf_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - struct bin_info *bin = NULL; - int ret; - int64_t vpid; - uint64_t baddr; - - ret = get_stream_event_context_int_field_value(err, - event, "_vpid", &vpid); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_payload_unsigned_int_field_value(err, - event, "_baddr", &baddr); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - 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 = get_payload_build_id_field_value(err, event, "_build_id", - &bin->build_id, &bin->build_id_len); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - 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; - - // TODO - // bin_info_set_build_id(bin, build_id, build_id_len); - -end: - return; -} - -static -void handle_statedump_debug_link_event(FILE *err, struct debug_info *debug_info, - struct bt_ctf_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 tmp; - int ret; - - ret = get_stream_event_context_int_field_value(err, event, - "_vpid", &vpid); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_payload_unsigned_int_field_value(err, - event, "_baddr", &baddr); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_payload_unsigned_int_field_value(err, event, "_crc32", &tmp); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - crc32 = (uint32_t) tmp; - - ret = get_payload_string_field_value(err, - event, "_filename", &filename); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - 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(FILE *err, struct debug_info *debug_info, - struct bt_ctf_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; - int ret; - - ret = get_payload_unsigned_int_field_value(err, - event, "_baddr", &baddr); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_payload_unsigned_int_field_value(err, - event, "_memsz", &memsz); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_payload_string_field_value(err, - event, "_path", &path); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - if (has_pic_field) { - uint64_t tmp; - - ret = get_payload_unsigned_int_field_value(err, - event, "_is_pic", &tmp); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - is_pic = (tmp == 1); - } else { - /* - * dlopen has no is_pic field, because the shared - * object is always PIC. - */ - is_pic = true; - } - - ret = get_stream_event_context_int_field_value(err, event, "_vpid", - &vpid); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - if (!path) { - goto end; - } - - if (memsz == 0) { - /* Ignore VDSO. */ - goto end; - } - - 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_statedump_bin_info_event(FILE *err, struct debug_info *debug_info, - struct bt_ctf_event *event) -{ - handle_bin_info_event(err, debug_info, event, true); -} - -static inline -void handle_lib_load_event(FILE *err, struct debug_info *debug_info, - struct bt_ctf_event *event) -{ - handle_bin_info_event(err, debug_info, event, false); -} - -static inline -void handle_lib_unload_event(FILE *err, struct debug_info *debug_info, - struct bt_ctf_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - uint64_t baddr; - int64_t vpid; - gpointer key_ptr = NULL; - int ret; - - ret = get_payload_unsigned_int_field_value(err, - event, "_baddr", &baddr); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - ret = get_stream_event_context_int_field_value(err, event, "_vpid", - &vpid); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - 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_ptr = (gpointer) &baddr; - (void) g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info, - key_ptr); -end: - return; -} - -static -void handle_statedump_start(FILE *err, struct debug_info *debug_info, - struct bt_ctf_event *event) -{ - struct proc_debug_info_sources *proc_dbg_info_src; - int64_t vpid; - int ret; - - ret = get_stream_event_context_int_field_value(err, event, - "_vpid", &vpid); - if (ret) { - fprintf(err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - ret = -1; - goto end; - } - - 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; -} - -BT_HIDDEN -void debug_info_handle_event(FILE *err, struct bt_ctf_event *event, - struct debug_info *debug_info) -{ - struct bt_ctf_event_class *event_class; - const char *event_name; - GQuark q_event_name; - - if (!debug_info || !event) { - goto end; - } - event_class = bt_ctf_event_get_class(event); - if (!event_class) { - goto end; - } - event_name = bt_ctf_event_class_get_name(event_class); - if (!event_name) { - goto end_put_class; - } - q_event_name = g_quark_try_string(event_name); - - if (q_event_name == debug_info->q_statedump_bin_info) { - /* State dump */ - handle_statedump_bin_info_event(err, 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_lib_load_event(err, debug_info, event); - } else if (q_event_name == debug_info->q_statedump_start) { - /* Start state dump */ - handle_statedump_start(err, debug_info, event); - } else if (q_event_name == debug_info->q_statedump_debug_link) { - /* Debug link info */ - handle_statedump_debug_link_event(err, debug_info, event); - } else if (q_event_name == debug_info->q_statedump_build_id) { - /* Build ID info */ - handle_statedump_build_id_event(err, debug_info, event); - } else if (q_event_name == debug_info-> q_lib_unload) { - handle_lib_unload_event(err, debug_info, event); - } - -end_put_class: - bt_put(event_class); -end: - return; -} diff --git a/plugins/debug-info/debug-info.h b/plugins/debug-info/debug-info.h deleted file mode 100644 index 41618b0a..00000000 --- a/plugins/debug-info/debug-info.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H -#define BABELTRACE_PLUGIN_DEBUG_INFO_H - -/* - * Babeltrace - Debug information Plug-in - * - * Copyright (c) 2015 EfficiOS Inc. - * Copyright (c) 2015 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 -#include -#include - -struct debug_info_component { - FILE *err; - char *arg_debug_info_field_name; - const char *arg_debug_dir; - bool arg_full_path; - const char *arg_target_prefix; -}; - -struct debug_info_iterator { - struct debug_info_component *debug_info_component; - /* Map between struct bt_ctf_trace and struct bt_ctf_writer. */ - GHashTable *trace_map; - /* Map between reader and writer stream. */ - GHashTable *stream_map; - /* Map between reader and writer stream class. */ - GHashTable *stream_class_map; - /* Map between reader and writer stream class. */ - GHashTable *packet_map; - /* Map between a trace_class and its corresponding debug_info. */ - GHashTable *trace_debug_map; - /* Input iterators associated with this output iterator. */ - GPtrArray *input_iterator_group; - struct bt_notification *current_notification; - struct bt_notification_iterator *input_iterator; - FILE *err; -}; - -struct debug_info_source { - /* Strings are owned by debug_info_source. */ - char *func; - uint64_t line_no; - char *src_path; - /* short_src_path points inside src_path, no need to free. */ - const char *short_src_path; - char *bin_path; - /* short_bin_path points inside bin_path, no need to free. */ - const char *short_bin_path; - /* - * Location within the binary. Either absolute (@0x1234) or - * relative (+0x4321). - */ - char *bin_loc; -}; - -BT_HIDDEN -struct debug_info *debug_info_create(struct debug_info_component *comp); - -BT_HIDDEN -void debug_info_destroy(struct debug_info *debug_info); - -BT_HIDDEN -struct debug_info_source *debug_info_query(struct debug_info *debug_info, - int64_t vpid, uint64_t ip); - -BT_HIDDEN -void debug_info_handle_event(FILE *err, struct bt_ctf_event *event, - struct debug_info *debug_info); - -#if 0 -static inline -void trace_debug_info_destroy(struct bt_ctf_trace *trace) -{ - debug_info_destroy(trace->debug_info); -} -#endif - -#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */ diff --git a/plugins/debug-info/dwarf.c b/plugins/debug-info/dwarf.c deleted file mode 100644 index 307bd2aa..00000000 --- a/plugins/debug-info/dwarf.c +++ /dev/null @@ -1,369 +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_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 = 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 = 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/debug-info/dwarf.h b/plugins/debug-info/dwarf.h deleted file mode 100644 index c3d56b78..00000000 --- a/plugins/debug-info/dwarf.h +++ /dev/null @@ -1,226 +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); - -/** - * 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/debug-info/plugin.c b/plugins/debug-info/plugin.c deleted file mode 100644 index 85b12a67..00000000 --- a/plugins/debug-info/plugin.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * plugin.c - * - * Babeltrace Debug Info Plug-in - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "debug-info.h" -#include "copy.h" - -static -void destroy_debug_info_data(struct debug_info_component *debug_info) -{ - free(debug_info->arg_debug_info_field_name); - g_free(debug_info); -} - -static -void destroy_debug_info_component(struct bt_private_component *component) -{ - void *data = bt_private_component_get_user_data(component); - destroy_debug_info_data(data); -} - -static -struct debug_info_component *create_debug_info_component_data(void) -{ - struct debug_info_component *debug_info; - - debug_info = g_new0(struct debug_info_component, 1); - if (!debug_info) { - goto end; - } - debug_info->err = stderr; - -end: - return debug_info; -} - -static -void unref_debug_info(struct debug_info *debug_info) -{ - debug_info_destroy(debug_info); -} - -static -void unref_trace(struct bt_ctf_trace *trace) -{ - bt_put(trace); -} - -static -void unref_stream(struct bt_ctf_stream *stream) -{ - bt_put(stream); -} - -static -void unref_packet(struct bt_ctf_packet *packet) -{ - bt_put(packet); -} - -static -void unref_stream_class(struct bt_ctf_stream_class *stream_class) -{ - bt_put(stream_class); -} - -static -void debug_info_iterator_destroy(struct bt_private_notification_iterator *it) -{ - struct debug_info_iterator *it_data; - - it_data = bt_private_notification_iterator_get_user_data(it); - assert(it_data); - - if (it_data->input_iterator_group) { - g_ptr_array_free(it_data->input_iterator_group, TRUE); - } - bt_put(it_data->current_notification); - bt_put(it_data->input_iterator); - g_hash_table_destroy(it_data->trace_map); - g_hash_table_destroy(it_data->stream_map); - g_hash_table_destroy(it_data->stream_class_map); - g_hash_table_destroy(it_data->packet_map); - g_hash_table_destroy(it_data->trace_debug_map); - g_free(it_data); -} - -static -struct bt_notification *handle_notification(FILE *err, - struct debug_info_iterator *debug_it, - struct bt_notification *notification) -{ - struct bt_notification *new_notification = NULL; - - switch (bt_notification_get_type(notification)) { - case BT_NOTIFICATION_TYPE_PACKET_BEGIN: - { - struct bt_ctf_packet *packet = - bt_notification_packet_begin_get_packet(notification); - struct bt_ctf_packet *writer_packet; - - if (!packet) { - goto end; - } - - writer_packet = debug_info_new_packet(debug_it, packet); - assert(writer_packet); - new_notification = bt_notification_packet_begin_create( - writer_packet); - assert(new_notification); - bt_put(packet); - break; - } - case BT_NOTIFICATION_TYPE_PACKET_END: - { - struct bt_ctf_packet *packet = - bt_notification_packet_end_get_packet(notification); - struct bt_ctf_packet *writer_packet; - - if (!packet) { - goto end; - } - - writer_packet = debug_info_close_packet(debug_it, packet); - assert(writer_packet); - new_notification = bt_notification_packet_end_create( - writer_packet); - assert(new_notification); - bt_put(packet); - bt_put(writer_packet); - break; - } - case BT_NOTIFICATION_TYPE_EVENT: - { - struct bt_ctf_event *event = bt_notification_event_get_event( - notification); - struct bt_ctf_event *writer_event; - struct bt_clock_class_priority_map *cc_prio_map = - bt_notification_event_get_clock_class_priority_map( - notification); - - if (!event) { - goto end; - } - writer_event = debug_info_output_event(debug_it, event); - assert(writer_event); - new_notification = bt_notification_event_create(writer_event, - cc_prio_map); - bt_put(cc_prio_map); - assert(new_notification); - bt_put(event); - bt_put(writer_event); - break; - } - case BT_NOTIFICATION_TYPE_STREAM_END: - { - struct bt_ctf_stream *stream = - bt_notification_stream_end_get_stream(notification); - struct bt_ctf_stream *writer_stream; - - if (!stream) { - goto end; - } - - writer_stream = debug_info_stream_end(debug_it, stream); - assert(writer_stream); - new_notification = bt_notification_stream_end_create( - writer_stream); - assert(new_notification); - bt_put(stream); - bt_put(writer_stream); - break; - } - default: - puts("Unhandled notification type"); - } - -end: - return new_notification; -} - -static -struct bt_notification_iterator_next_return debug_info_iterator_next( - struct bt_private_notification_iterator *iterator) -{ - struct debug_info_iterator *debug_it = NULL; - struct bt_private_component *component = NULL; - struct debug_info_component *debug_info = NULL; - struct bt_notification_iterator *source_it = NULL; - struct bt_notification *notification; - struct bt_notification_iterator_next_return ret = { - .status = BT_NOTIFICATION_ITERATOR_STATUS_OK, - .notification = NULL, - }; - - debug_it = bt_private_notification_iterator_get_user_data(iterator); - assert(debug_it); - - component = bt_private_notification_iterator_get_private_component(iterator); - assert(component); - debug_info = bt_private_component_get_user_data(component); - assert(debug_info); - - source_it = debug_it->input_iterator; - - ret.status = bt_notification_iterator_next(source_it); - if (ret.status != BT_NOTIFICATION_ITERATOR_STATUS_OK) { - goto end; - } - - notification = bt_notification_iterator_get_notification( - source_it); - if (!notification) { - ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; - goto end; - } - - ret.notification = handle_notification(debug_info->err, debug_it, - notification); - assert(ret.notification); - bt_put(notification); - -end: - bt_put(component); - return ret; -} - -/* -static -struct bt_notification *debug_info_iterator_get( - struct bt_private_notification_iterator *iterator) -{ - struct debug_info_iterator *debug_it; - - debug_it = bt_private_notification_iterator_get_user_data(iterator); - assert(debug_it); - - if (!debug_it->current_notification) { - enum bt_notification_iterator_status it_ret; - - it_ret = debug_info_iterator_next(iterator); - if (it_ret) { - goto end; - } - } - -end: - return bt_get(debug_it->current_notification); -} -*/ - -static -enum bt_notification_iterator_status debug_info_iterator_seek_time( - struct bt_private_notification_iterator *iterator, int64_t time) -{ - enum bt_notification_iterator_status ret; - - ret = BT_NOTIFICATION_ITERATOR_STATUS_OK; - - return ret; -} - -static -enum bt_notification_iterator_status debug_info_iterator_init( - struct bt_private_notification_iterator *iterator, - struct bt_private_port *port) -{ - enum bt_notification_iterator_status ret = - BT_NOTIFICATION_ITERATOR_STATUS_OK; - enum bt_notification_iterator_status it_ret; - struct bt_private_port *input_port = NULL; - struct bt_private_connection *connection = NULL; - struct bt_private_component *component = - bt_private_notification_iterator_get_private_component(iterator); - struct debug_info_iterator *it_data = g_new0(struct debug_info_iterator, 1); - - if (!it_data) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; - goto end; - } - - /* Create a new iterator on the upstream component. */ - input_port = bt_private_component_filter_get_input_private_port_by_name( - component, "in"); - assert(input_port); - connection = bt_private_port_get_private_connection(input_port); - assert(connection); - - it_data->input_iterator = bt_private_connection_create_notification_iterator( - connection, NULL); - if (!it_data->input_iterator) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; - goto end; - } - it_data->debug_info_component = (struct debug_info_component *) - bt_private_component_get_user_data(component); - - it_data->err = it_data->debug_info_component->err; - it_data->trace_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) unref_trace); - it_data->stream_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) unref_stream); - it_data->stream_class_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) unref_stream_class); - it_data->packet_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) unref_packet); - it_data->trace_debug_map = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) unref_debug_info); - - it_ret = bt_private_notification_iterator_set_user_data(iterator, it_data); - if (it_ret) { - goto end; - } - -end: - bt_put(connection); - bt_put(input_port); - return ret; -} - -static -enum bt_component_status init_from_params( - struct debug_info_component *debug_info_component, - struct bt_value *params) -{ - struct bt_value *value = NULL; - enum bt_component_status ret = BT_COMPONENT_STATUS_OK; - - assert(params); - - value = bt_value_map_get(params, "debug-info-field-name"); - if (value) { - enum bt_value_status value_ret; - const char *tmp; - - value_ret = bt_value_string_get(value, &tmp); - if (value_ret) { - ret = BT_COMPONENT_STATUS_INVALID; - printf_error("Failed to retrieve debug-info-field-name value. " - "Expecting a string"); - } - strcpy(debug_info_component->arg_debug_info_field_name, tmp); - bt_put(value); - } else { - debug_info_component->arg_debug_info_field_name = - malloc(strlen("debug_info") + 1); - if (!debug_info_component->arg_debug_info_field_name) { - ret = BT_COMPONENT_STATUS_NOMEM; - printf_error(); - } - sprintf(debug_info_component->arg_debug_info_field_name, - "debug_info"); - } - if (ret != BT_COMPONENT_STATUS_OK) { - goto end; - } - - value = bt_value_map_get(params, "debug-dir"); - if (value) { - enum bt_value_status value_ret; - - value_ret = bt_value_string_get(value, - &debug_info_component->arg_debug_dir); - if (value_ret) { - ret = BT_COMPONENT_STATUS_INVALID; - printf_error("Failed to retrieve debug-dir value. " - "Expecting a string"); - } - } - bt_put(value); - if (ret != BT_COMPONENT_STATUS_OK) { - goto end; - } - - value = bt_value_map_get(params, "target-prefix"); - if (value) { - enum bt_value_status value_ret; - - value_ret = bt_value_string_get(value, - &debug_info_component->arg_target_prefix); - if (value_ret) { - ret = BT_COMPONENT_STATUS_INVALID; - printf_error("Failed to retrieve target-prefix value. " - "Expecting a string"); - } - } - bt_put(value); - if (ret != BT_COMPONENT_STATUS_OK) { - goto end; - } - - value = bt_value_map_get(params, "full-path"); - if (value) { - enum bt_value_status value_ret; - - value_ret = bt_value_bool_get(value, - &debug_info_component->arg_full_path); - if (value_ret) { - ret = BT_COMPONENT_STATUS_INVALID; - printf_error("Failed to retrieve full-path value. " - "Expecting a boolean"); - } - } - bt_put(value); - if (ret != BT_COMPONENT_STATUS_OK) { - goto end; - } - -end: - return ret; -} - -enum bt_component_status debug_info_component_init( - struct bt_private_component *component, struct bt_value *params, - UNUSED_VAR void *init_method_data) -{ - enum bt_component_status ret; - struct debug_info_component *debug_info = create_debug_info_component_data(); - - if (!debug_info) { - ret = BT_COMPONENT_STATUS_NOMEM; - goto end; - } - - ret = bt_private_component_set_user_data(component, debug_info); - if (ret != BT_COMPONENT_STATUS_OK) { - goto error; - } - - ret = init_from_params(debug_info, params); -end: - return ret; -error: - destroy_debug_info_data(debug_info); - return ret; -} - -/* Initialize plug-in entry points. */ -BT_PLUGIN(debug_info); -BT_PLUGIN_DESCRIPTION("Babeltrace Debug Informations Plug-In."); -BT_PLUGIN_AUTHOR("Julien Desfossez"); -BT_PLUGIN_LICENSE("MIT"); - -BT_PLUGIN_FILTER_COMPONENT_CLASS(debug_info, debug_info_iterator_next); -BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(debug_info, - "Add the debug information to events if possible."); -BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(debug_info, debug_info_component_init); -BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(debug_info, destroy_debug_info_component); -BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD(debug_info, - debug_info_iterator_init); -BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_FINALIZE_METHOD(debug_info, - debug_info_iterator_destroy); -BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_SEEK_TIME_METHOD(debug_info, - debug_info_iterator_seek_time); diff --git a/plugins/debug-info/utils.c b/plugins/debug-info/utils.c deleted file mode 100644 index 80dc87de..00000000 --- a/plugins/debug-info/utils.c +++ /dev/null @@ -1,52 +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; -} diff --git a/plugins/debug-info/utils.h b/plugins/debug-info/utils.h deleted file mode 100644 index d2a08c06..00000000 --- a/plugins/debug-info/utils.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _BABELTRACE_DEBUG_INFO_UTILS_H -#define _BABELTRACE_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 - -/* - * 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); - -#endif /* _BABELTRACE_DEBUG_INFO_UTILS_H */ diff --git a/plugins/lttng-utils/Makefile.am b/plugins/lttng-utils/Makefile.am new file mode 100644 index 00000000..97a327bb --- /dev/null +++ b/plugins/lttng-utils/Makefile.am @@ -0,0 +1,26 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins \ + -I$(top_srcdir)/plugins/libctfcopytrace + +SUBDIRS = . + +plugindir = "$(PLUGINSDIR)" +plugin_LTLIBRARIES = libbabeltrace-plugin-debug-info.la + +noinst_HEADERS = \ + crc32.h \ + debug-info.h \ + dwarf.h \ + bin-info.h \ + utils.h \ + copy.h + +libbabeltrace_plugin_debug_info_la_SOURCES = \ + plugin.c debug-info.h debug-info.c bin-info.c dwarf.c crc32.c utils.c \ + copy.c + +libbabeltrace_plugin_debug_info_la_LDFLAGS = \ + -version-info $(BABELTRACE_LIBRARY_VERSION) -lelf -ldw + +libbabeltrace_plugin_debug_info_la_LIBADD = \ + $(top_builddir)/lib/libbabeltrace.la \ + $(top_builddir)/plugins/libctfcopytrace/libctfcopytrace.la diff --git a/plugins/lttng-utils/bin-info.c b/plugins/lttng-utils/bin-info.c new file mode 100644 index 00000000..170b351f --- /dev/null +++ b/plugins/lttng-utils/bin-info.c @@ -0,0 +1,1358 @@ +/* + * 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. + */ + +#include +#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 + +BT_HIDDEN +int bin_info_init(void) +{ + int ret = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) { + printf_debug("ELF library initialization failed: %s\n", + 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 = strdup(path); + } + + if (!bin->elf_path) { + goto error; + } + + if (debug_info_dir) { + bin->debug_info_dir = 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; + + 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); + + free(bin->debug_info_dir); + free(bin->elf_path); + free(bin->dwarf_path); + g_free(bin->build_id); + free(bin->dbg_link_filename); + + elf_end(bin->elf_file); + + close(bin->elf_fd); + close(bin->dwarf_fd); + + g_free(bin); +} + + +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; + } + + bin->build_id = malloc(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; + + /* + * 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 = 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 = 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 ? : 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 = malloc(build_id_file_len); + if (!build_id_file) { + goto error; + } + + 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); + + snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); + } + strcat(build_id_file, BUILD_ID_SUFFIX); + + 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 + * build ID 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 char *dbg_dir = NULL; + char *dir_name = NULL, *bin_dir = NULL, *path = NULL; + size_t max_path_len = 0; + + if (!bin || !bin->dbg_link_filename) { + goto error; + } + + dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR; + + dir_name = dirname(bin->elf_path); + if (!dir_name) { + goto error; + } + + /* bin_dir is just dir_name with a trailing slash */ + bin_dir = malloc(strlen(dir_name) + 2); + if (!bin_dir) { + goto error; + } + + strcpy(bin_dir, dir_name); + strcat(bin_dir, "/"); + + max_path_len = strlen(dbg_dir) + strlen(bin_dir) + + strlen(DEBUG_SUBDIR) + strlen(bin->dbg_link_filename) + + 1; + path = malloc(max_path_len); + if (!path) { + goto error; + } + + /* First look in the executable's dir */ + strcpy(path, bin_dir); + strcat(path, bin->dbg_link_filename); + + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + + /* If not found, look in .debug subdir */ + strcpy(path, bin_dir); + strcat(path, DEBUG_SUBDIR); + strcat(path, bin->dbg_link_filename); + + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + + /* Lastly, look under the global debug directory */ + strcpy(path, dbg_dir); + strcat(path, bin_dir); + strcat(path, bin->dbg_link_filename); + + if (is_valid_debug_file(path, bin->dbg_link_crc)) { + goto found; + } + +error: + ret = -1; +end: + free(path); + free(bin_dir); + + 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; +} + +/** + * 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; + printf_verbose("Failed to open %s\n", bin->elf_path); + goto error; + } + + elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); + if (!elf_file) { + printf_debug("elf_begin failed: %s\n", elf_errmsg(-1)); + goto error; + } + + if (elf_kind(elf_file) != ELF_K_ELF) { + printf_verbose("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; +} + +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) +{ + int ret; + uint64_t offset; + char *_result = NULL; + char offset_str[ADDR_STR_LEN]; + + if (!base_str || !result) { + goto error; + } + + offset = high_addr - low_addr; + + _result = malloc(strlen(base_str) + ADDR_STR_LEN); + if (!_result) { + goto error; + } + + ret = snprintf(offset_str, ADDR_STR_LEN, "+%#0" PRIx64, offset); + if (ret < 0) { + goto error; + } + strcpy(_result, base_str); + strcat(_result, offset_str); + *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; + } + + /* 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) { + printf_verbose("Failed to set bin dwarf info, falling back to ELF lookup.\n"); + /* 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); + printf_verbose("Failed to lookup function name (elf), error %i\n", ret); + } else { + ret = bin_info_lookup_dwarf_function_name(bin, addr, &_func_name); + printf_verbose("Failed to lookup function name (dwarf), error %i\n", 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) +{ + int ret = 0; + char *_bin_loc = NULL; + + if (!bin || !bin_loc) { + goto error; + } + + if (bin->is_pic) { + addr -= bin->low_addr; + ret = asprintf(&_bin_loc, "+%#0" PRIx64, addr); + } else { + ret = asprintf(&_bin_loc, "@%#0" PRIx64, addr); + } + + if (ret == -1 || !_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 { + int tag; + + ret = bt_dwarf_die_get_tag(die, &tag); + if (ret) { + goto error; + } + + if (tag == DW_TAG_inlined_subroutine) { + ret = bt_dwarf_die_contains_addr(die, addr, &_contains); + if (ret) { + goto error; + } + + if (_contains) { + goto end; + } + } + } 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 = 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; + } + + /* 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 new file mode 100644 index 00000000..05d0d797 --- /dev/null +++ b/plugins/lttng-utils/bin-info.h @@ -0,0 +1,233 @@ +#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. */ + char *elf_path; + char *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. */ + char *dbg_link_filename; + uint32_t dbg_link_crc; + /* FDs to ELF and DWARF files. */ + int elf_fd; + int dwarf_fd; + /* Configuration. */ + char *debug_info_dir; + /* Denotes whether the executable is position independent code. */ + bool is_pic: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; + char *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/copy.c b/plugins/lttng-utils/copy.c new file mode 100644 index 00000000..2689a703 --- /dev/null +++ b/plugins/lttng-utils/copy.c @@ -0,0 +1,1674 @@ +/* + * copy.c + * + * Babeltrace Copy Trace Structure + * + * Copyright 2017 Julien Desfossez + * + * Author: Julien Desfossez + * + * 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 +#include +#include +#include +#include + +#include +#include "debug-info.h" + +static +struct bt_ctf_field *get_payload_field(FILE *err, + struct bt_ctf_event *event, const char *field_name) +{ + struct bt_ctf_field *field = NULL, *sec = NULL; + struct bt_ctf_field_type *sec_type = NULL; + + sec = bt_ctf_event_get_payload(event, NULL); + if (!sec) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + sec_type = bt_ctf_field_get_type(sec); + if (!sec_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + if (bt_ctf_field_type_get_type_id(sec_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_field_structure_get_field(sec, field_name); + +end: + bt_put(sec_type); + bt_put(sec); + return field; +} + +static +struct bt_ctf_field *get_stream_event_context_field(FILE *err, + struct bt_ctf_event *event, const char *field_name) +{ + struct bt_ctf_field *field = NULL, *sec = NULL; + struct bt_ctf_field_type *sec_type = NULL; + + sec = bt_ctf_event_get_stream_event_context(event); + if (!sec) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + sec_type = bt_ctf_field_get_type(sec); + if (!sec_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + if (bt_ctf_field_type_get_type_id(sec_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_field_structure_get_field(sec, field_name); + +end: + bt_put(sec_type); + bt_put(sec); + return field; +} + +BT_HIDDEN +int get_stream_event_context_unsigned_int_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint64_t *value) +{ + int ret; + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + + field = get_stream_event_context_field(err, event, field_name); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_unsigned_integer_get_value(field, value); + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +BT_HIDDEN +int get_stream_event_context_int_field_value(FILE *err, struct bt_ctf_event *event, + const char *field_name, int64_t *value) +{ + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + int ret; + + field = get_stream_event_context_field(err, event, field_name); + if (!field) { + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_signed_integer_get_value(field, value); + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +BT_HIDDEN +int get_payload_unsigned_int_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint64_t *value) +{ + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + int ret; + + field = get_payload_field(err, event, field_name); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_unsigned_integer_get_value(field, value); + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +BT_HIDDEN +int get_payload_int_field_value(FILE *err, struct bt_ctf_event *event, + const char *field_name, int64_t *value) +{ + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + int ret; + + field = get_payload_field(err, event, field_name); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_signed_integer_get_value(field, value); + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +BT_HIDDEN +int get_payload_string_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + const char **value) +{ + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + int ret; + + field = get_payload_field(err, event, field_name); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_STRING) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + *value = bt_ctf_field_string_get_value(field); + if (!*value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +BT_HIDDEN +int get_payload_build_id_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint8_t **build_id, uint64_t *build_id_len) +{ + struct bt_ctf_field *field = NULL, *seq_len = NULL; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field *seq_field = NULL; + uint64_t i; + int ret; + + *build_id = NULL; + + field = get_payload_field(err, event, field_name); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field_type = bt_ctf_field_get_type(field); + if (!field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(field_type); + + seq_len = bt_ctf_field_sequence_get_length(field); + if (!seq_len) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_unsigned_integer_get_value(seq_len, build_id_len); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(seq_len); + + *build_id = g_new0(uint8_t, *build_id_len); + if (!*build_id) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + for (i = 0; i < *build_id_len; i++) { + uint64_t tmp; + + seq_field = bt_ctf_field_sequence_get_field(field, i); + if (!seq_field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_unsigned_integer_get_value(seq_field, &tmp); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(seq_field); + (*build_id)[i] = (uint8_t) tmp; + } + ret = 0; + goto end; + +error: + g_free(*build_id); + ret = -1; +end: + bt_put(field_type); + bt_put(field); + return ret; +} + +static +struct debug_info *lookup_trace_debug_info(struct debug_info_iterator *debug_it, + struct bt_ctf_trace *writer_trace) +{ + return (struct debug_info *) g_hash_table_lookup( + debug_it->trace_debug_map, + (gpointer) writer_trace); +} + +static +struct debug_info *insert_new_debug_info(struct debug_info_iterator *debug_it, + struct bt_ctf_trace *writer_trace) +{ + struct debug_info *debug_info = NULL; + struct bt_value *field = NULL; + const char *str_value; + enum bt_value_status ret; + + field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, + "domain"); + /* No domain field, no debug info */ + if (!field) { + goto end; + } + ret = bt_value_string_get(field, &str_value); + if (ret != BT_VALUE_STATUS_OK) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + /* Domain not ust, no debug info */ + if (strcmp(str_value, "ust") != 0) { + goto end; + } + BT_PUT(field); + + /* No tracer_name, no debug info */ + field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, + "tracer_name"); + /* No tracer_name, no debug info */ + if (!field) { + goto end; + } + ret = bt_value_string_get(field, &str_value); + if (ret != BT_VALUE_STATUS_OK) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + /* Tracer_name not lttng-ust, no debug info */ + if (strcmp(str_value, "lttng-ust") != 0) { + goto end; + } + BT_PUT(field); + + debug_info = debug_info_create(debug_it->debug_info_component); + if (!debug_info) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + g_hash_table_insert(debug_it->trace_debug_map, (gpointer) writer_trace, + debug_info); + +end: + bt_put(field); + return debug_info; +} + +static +struct debug_info *get_trace_debug_info(struct debug_info_iterator *debug_it, + struct bt_ctf_trace *writer_trace) +{ + struct debug_info *debug_info; + + debug_info = lookup_trace_debug_info(debug_it, writer_trace); + if (debug_info) { + goto end; + } + + debug_info = insert_new_debug_info(debug_it, writer_trace); + +end: + return debug_info; +} + +static +struct bt_ctf_trace *lookup_trace(struct debug_info_iterator *debug_it, + struct bt_ctf_trace *trace) +{ + return (struct bt_ctf_trace *) g_hash_table_lookup( + debug_it->trace_map, + (gpointer) trace); +} + +static +struct bt_ctf_trace *insert_new_trace(struct debug_info_iterator *debug_it, + struct bt_ctf_trace *trace) { + struct bt_ctf_trace *writer_trace = NULL; + int ret; + + writer_trace = bt_ctf_trace_create(); + if (!writer_trace) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + g_hash_table_insert(debug_it->trace_map, (gpointer) trace, writer_trace); + + ret = ctf_copy_trace(debug_it->err, trace, writer_trace); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + goto end; + +error: + BT_PUT(writer_trace); +end: + return writer_trace; +} + +static +struct bt_ctf_packet *lookup_packet(struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet) +{ + return (struct bt_ctf_packet *) g_hash_table_lookup( + debug_it->packet_map, + (gpointer) packet); +} + +static +struct bt_ctf_packet *insert_new_packet(struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet, + struct bt_ctf_stream *writer_stream) +{ + struct bt_ctf_packet *writer_packet; + + writer_packet = bt_ctf_packet_create(writer_stream); + if (!writer_packet) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + g_hash_table_insert(debug_it->packet_map, (gpointer) packet, writer_packet); + +end: + return writer_packet; +} + +static +int add_debug_info_fields(FILE *err, + struct bt_ctf_field_type *writer_event_context_type, + struct debug_info_component *component) +{ + struct bt_ctf_field_type *ip_field = NULL, *debug_field_type = NULL, + *bin_field_type = NULL, *func_field_type = NULL, + *src_field_type = NULL; + int ret = 0; + + ip_field = bt_ctf_field_type_structure_get_field_type_by_name( + writer_event_context_type, "_ip"); + /* No ip field, so no debug info. */ + if (!ip_field) { + goto end; + } + BT_PUT(ip_field); + + debug_field_type = bt_ctf_field_type_structure_get_field_type_by_name( + writer_event_context_type, + component->arg_debug_info_field_name); + /* Already existing debug_info field, no need to add it. */ + if (debug_field_type) { + goto end; + } + + debug_field_type = bt_ctf_field_type_structure_create(); + if (!debug_field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + bin_field_type = bt_ctf_field_type_string_create(); + if (!bin_field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + func_field_type = bt_ctf_field_type_string_create(); + if (!func_field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + src_field_type = bt_ctf_field_type_string_create(); + if (!src_field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_field_type_structure_add_field(debug_field_type, + bin_field_type, "bin"); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_field_type_structure_add_field(debug_field_type, + func_field_type, "func"); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_field_type_structure_add_field(debug_field_type, + src_field_type, "src"); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, + debug_field_type, component->arg_debug_info_field_name); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = 0; + goto end; + +error: + BT_PUT(debug_field_type); + ret = -1; +end: + bt_put(src_field_type); + bt_put(func_field_type); + bt_put(bin_field_type); + bt_put(debug_field_type); + return ret; +} + +static +int create_debug_info_event_context_type(FILE *err, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *writer_event_context_type, + struct debug_info_component *component) +{ + int ret, nr_fields, i; + + nr_fields = bt_ctf_field_type_structure_get_field_count(event_context_type); + for (i = 0; i < nr_fields; i++) { + struct bt_ctf_field_type *field_type = NULL; + const char *field_name; + + if (bt_ctf_field_type_structure_get_field(event_context_type, + &field_name, &field_type, i) < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, + field_type, field_name); + BT_PUT(field_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + } + + ret = add_debug_info_fields(err, writer_event_context_type, + component); + goto end; + +error: + ret = -1; +end: + return ret; +} + +static +struct bt_ctf_stream_class *copy_stream_class_debug_info(FILE *err, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_trace *writer_trace, + struct debug_info_component *component) +{ + struct bt_ctf_field_type *type = NULL; + struct bt_ctf_stream_class *writer_stream_class = NULL; + struct bt_ctf_field_type *writer_event_context_type = NULL; + int ret_int; + const char *name = bt_ctf_stream_class_get_name(stream_class); + + if (strlen(name) == 0) { + name = NULL; + } + + writer_stream_class = bt_ctf_stream_class_create(name); + if (!writer_stream_class) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + type = bt_ctf_stream_class_get_packet_context_type(stream_class); + if (!type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret_int = bt_ctf_stream_class_set_packet_context_type( + writer_stream_class, type); + if (ret_int < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + BT_PUT(type); + + type = bt_ctf_stream_class_get_event_header_type(stream_class); + if (!type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret_int = bt_ctf_stream_class_set_event_header_type( + writer_stream_class, type); + if (ret_int < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + BT_PUT(type); + + type = bt_ctf_stream_class_get_event_context_type(stream_class); + if (type) { + writer_event_context_type = bt_ctf_field_type_structure_create(); + if (!writer_event_context_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + ret_int = create_debug_info_event_context_type(err, type, + writer_event_context_type, component); + if (ret_int) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + BT_PUT(type); + + ret_int = bt_ctf_stream_class_set_event_context_type( + writer_stream_class, writer_event_context_type); + if (ret_int < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + BT_PUT(writer_event_context_type); + } + + goto end; + +error: + BT_PUT(writer_stream_class); +end: + bt_put(writer_event_context_type); + bt_put(type); + return writer_stream_class; +} + +/* + * Add the original clock classes to the new trace, we do not need to copy + * them, and if we did, we would have to manually inspect the stream class + * to update the integers mapping to a clock. + */ +static +int add_clock_classes(FILE *err, struct bt_ctf_trace *writer_trace, + struct bt_ctf_stream_class *writer_stream_class, + struct bt_ctf_trace *trace) +{ + int ret, clock_class_count, i; + + clock_class_count = bt_ctf_trace_get_clock_class_count(trace); + + for (i = 0; i < clock_class_count; i++) { + struct bt_ctf_clock_class *clock_class = + bt_ctf_trace_get_clock_class_by_index(trace, i); + + if (!clock_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_trace_add_clock_class(writer_trace, clock_class); + BT_PUT(clock_class); + if (ret != 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + return ret; + +} + +static +struct bt_ctf_stream_class *insert_new_stream_class( + struct debug_info_iterator *debug_it, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_stream_class *writer_stream_class = NULL; + struct bt_ctf_trace *trace, *writer_trace = NULL; + enum bt_component_status ret; + int int_ret; + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (!trace) { + fprintf(debug_it->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + writer_trace = lookup_trace(debug_it, trace); + if (!writer_trace) { + writer_trace = insert_new_trace(debug_it, trace); + if (!writer_trace) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto error; + } + } + bt_get(writer_trace); + + writer_stream_class = copy_stream_class_debug_info(debug_it->err, stream_class, + writer_trace, debug_it->debug_info_component); + if (!writer_stream_class) { + fprintf(debug_it->err, "[error] Failed to copy stream class\n"); + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + int_ret = bt_ctf_trace_add_stream_class(writer_trace, writer_stream_class); + if (int_ret) { + fprintf(debug_it->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = add_clock_classes(debug_it->err, writer_trace, + writer_stream_class, trace); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(debug_it->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + BT_PUT(writer_trace); + BT_PUT(trace); + + g_hash_table_insert(debug_it->stream_class_map, + (gpointer) stream_class, writer_stream_class); + + goto end; + +error: + BT_PUT(writer_stream_class); +end: + bt_put(trace); + bt_put(writer_trace); + return writer_stream_class; +} + +static +struct bt_ctf_stream *insert_new_stream( + struct debug_info_iterator *debug_it, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream *writer_stream = NULL; + struct bt_ctf_stream_class *writer_stream_class = NULL; + + writer_stream_class = g_hash_table_lookup( + debug_it->stream_class_map, + (gpointer) stream_class); + + if (!writer_stream_class) { + writer_stream_class = insert_new_stream_class(debug_it, + stream_class); + if (!writer_stream_class) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + } + bt_get(writer_stream_class); + + writer_stream = bt_ctf_stream_create(writer_stream_class, + bt_ctf_stream_get_name(stream)); + if (!writer_stream) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + g_hash_table_insert(debug_it->stream_map, (gpointer) stream, + writer_stream); + + goto end; + +error: + BT_PUT(writer_stream); +end: + bt_put(writer_stream_class); + return writer_stream; +} + +static +struct bt_ctf_stream *lookup_stream(struct debug_info_iterator *debug_it, + struct bt_ctf_stream *stream) +{ + return (struct bt_ctf_stream *) g_hash_table_lookup( + debug_it->stream_map, + (gpointer) stream); +} + +static +struct bt_ctf_event_class *get_event_class(struct debug_info_iterator *debug_it, + struct bt_ctf_stream_class *writer_stream_class, + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_stream_class_get_event_class_by_id(writer_stream_class, + bt_ctf_event_class_get_id(event_class)); +} + +static +struct bt_ctf_stream *get_writer_stream( + struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet, struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_stream *writer_stream = NULL; + + stream_class = bt_ctf_stream_get_class(stream); + if (!stream_class) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + writer_stream = lookup_stream(debug_it, stream); + if (!writer_stream) { + writer_stream = insert_new_stream(debug_it, stream_class, stream); + } + bt_get(writer_stream); + + goto end; + +error: + BT_PUT(writer_stream); +end: + bt_put(stream_class); + return writer_stream; +} + +BT_HIDDEN +struct bt_ctf_packet *debug_info_new_packet( + struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet) +{ + struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; + struct bt_ctf_field *writer_packet_context = NULL; + struct bt_ctf_packet *writer_packet = NULL; + int int_ret; + + stream = bt_ctf_packet_get_stream(packet); + if (!stream) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + writer_stream = get_writer_stream(debug_it, packet, stream); + if (!writer_stream) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + /* + * If a packet was already opened, close it and remove it from + * the HT. + */ + writer_packet = lookup_packet(debug_it, packet); + if (writer_packet) { + g_hash_table_remove(debug_it->packet_map, packet); + BT_PUT(writer_packet); + } + + writer_packet = insert_new_packet(debug_it, packet, writer_stream); + if (!writer_packet) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + bt_get(writer_packet); + + writer_packet_context = ctf_copy_packet_context(debug_it->err, packet, + writer_stream); + if (!writer_packet_context) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + int_ret = bt_ctf_packet_set_context(writer_packet, writer_packet_context); + if (int_ret) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + goto end; + +error: + +end: + bt_put(writer_packet_context); + bt_put(writer_stream); + bt_put(stream); + return writer_packet; +} + +BT_HIDDEN +struct bt_ctf_packet *debug_info_close_packet( + struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet) +{ + struct bt_ctf_packet *writer_packet = NULL; + + writer_packet = lookup_packet(debug_it, packet); + if (!writer_packet) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + g_hash_table_remove(debug_it->packet_map, packet); + +end: + return writer_packet; +} + +BT_HIDDEN +struct bt_ctf_stream *debug_info_stream_end(struct debug_info_iterator *debug_it, + struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream *writer_stream; + + writer_stream = lookup_stream(debug_it, stream); + if (!writer_stream) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + g_hash_table_remove(debug_it->stream_map, stream); + +end: + return writer_stream; +} + +static +struct debug_info_source *lookup_debug_info(FILE *err, + struct bt_ctf_event *event, + struct debug_info *debug_info) +{ + int64_t vpid; + uint64_t ip; + struct debug_info_source *dbg_info_src = NULL; + int ret; + + ret = get_stream_event_context_int_field_value(err, event, + "_vpid", &vpid); + if (ret) { + goto end; + } + + ret = get_stream_event_context_unsigned_int_field_value(err, event, + "_ip", &ip); + if (ret) { + goto end; + } + + /* Get debug info for this context. */ + dbg_info_src = debug_info_query(debug_info, vpid, ip); + +end: + return dbg_info_src; +} + +static +int set_debug_info_field(FILE *err, struct bt_ctf_field *debug_field, + struct debug_info_source *dbg_info_src, + struct debug_info_component *component) +{ + int i, nr_fields, ret; + struct bt_ctf_field_type *debug_field_type = NULL; + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *field_type = NULL; + + debug_field_type = bt_ctf_field_get_type(debug_field); + if (!debug_field_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + nr_fields = bt_ctf_field_type_structure_get_field_count(debug_field_type); + for (i = 0; i < nr_fields; i++) { + const char *field_name; + + if (bt_ctf_field_type_structure_get_field(debug_field_type, + &field_name, &field_type, i) < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(field_type); + + field = bt_ctf_field_structure_get_field_by_index(debug_field, i); + if (!strcmp(field_name, "bin")) { + if (dbg_info_src && dbg_info_src->bin_path) { + GString *tmp = g_string_new(NULL); + + if (component->arg_full_path) { + g_string_printf(tmp, "%s%s", + dbg_info_src->bin_path, + dbg_info_src->bin_loc); + } else { + g_string_printf(tmp, "%s%s", + dbg_info_src->short_bin_path, + dbg_info_src->bin_loc); + } + ret = bt_ctf_field_string_set_value(field, tmp->str); + g_string_free(tmp, true); + } else { + ret = bt_ctf_field_string_set_value(field, ""); + } + } else if (!strcmp(field_name, "func")) { + if (dbg_info_src && dbg_info_src->func) { + ret = bt_ctf_field_string_set_value(field, + dbg_info_src->func); + } else { + ret = bt_ctf_field_string_set_value(field, ""); + } + } else if (!strcmp(field_name, "src")) { + if (dbg_info_src && dbg_info_src->src_path) { + GString *tmp = g_string_new(NULL); + + if (component->arg_full_path) { + g_string_printf(tmp, "%s:%" PRId64, + dbg_info_src->src_path, + dbg_info_src->line_no); + } else { + g_string_printf(tmp, "%s:%" PRId64, + dbg_info_src->short_src_path, + dbg_info_src->line_no); + } + ret = bt_ctf_field_string_set_value(field, tmp->str); + g_string_free(tmp, true); + } else { + ret = bt_ctf_field_string_set_value(field, ""); + } + } + BT_PUT(field); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + } + ret = 0; + goto end; + +error: + ret = -1; +end: + bt_put(field_type); + bt_put(field); + bt_put(debug_field_type); + return ret; +} + +static +int copy_set_debug_info_stream_event_context(FILE *err, + struct bt_ctf_field *event_context, + struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, + struct debug_info *debug_info, + struct debug_info_component *component) +{ + struct bt_ctf_field_type *writer_event_context_type = NULL; + struct bt_ctf_field *writer_event_context = NULL; + struct bt_ctf_field *field = NULL, *copy_field = NULL, *debug_field = NULL; + struct bt_ctf_field_type *field_type = NULL; + struct debug_info_source *dbg_info_src; + int ret, nr_fields, i; + + writer_event_context = bt_ctf_event_get_stream_event_context(writer_event); + if (!writer_event_context) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto error; + } + + writer_event_context_type = bt_ctf_field_get_type(writer_event_context); + if (!writer_event_context_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + /* + * If it is not a structure, we did not modify it to add the debug info + * fields, so just assign it as is. + */ + if (bt_ctf_field_type_get_type_id(writer_event_context_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { + ret = bt_ctf_event_set_event_context(writer_event, event_context); + goto end; + } + + dbg_info_src = lookup_debug_info(err, event, debug_info); + + nr_fields = bt_ctf_field_type_structure_get_field_count(writer_event_context_type); + for (i = 0; i < nr_fields; i++) { + const char *field_name; + + if (bt_ctf_field_type_structure_get_field(writer_event_context_type, + &field_name, &field_type, i) < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field = bt_ctf_field_structure_get_field_by_index(event_context, i); + /* + * The debug_info field, only exists in the writer event or + * if it was set by a earlier pass of the debug_info plugin. + * + * FIXME: are we replacing an exisiting debug_info struct here ?? + */ + if (!strcmp(field_name, component->arg_debug_info_field_name) && + !field) { + debug_field = bt_ctf_field_structure_get_field_by_index( + writer_event_context, i); + if (!debug_field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + ret = set_debug_info_field(err, debug_field, + dbg_info_src, component); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(debug_field); + } else { + copy_field = bt_ctf_field_copy(field); + if (!copy_field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = bt_ctf_field_structure_set_field(writer_event_context, + field_name, copy_field); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(copy_field); + } + BT_PUT(field_type); + BT_PUT(field); + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + bt_put(writer_event_context_type); + bt_put(writer_event_context); + bt_put(field); + bt_put(copy_field); + bt_put(debug_field); + bt_put(field_type); + return ret; +} + +static +struct bt_ctf_clock_class *stream_class_get_clock_class(FILE *err, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_clock_class *clock_class = NULL; + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (!trace) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + /* FIXME multi-clock? */ + clock_class = bt_ctf_trace_get_clock_class_by_index(trace, 0); + + bt_put(trace); + +end: + return clock_class; +} + +static +struct bt_ctf_clock_class *event_get_clock_class(FILE *err, struct bt_ctf_event *event) +{ + struct bt_ctf_event_class *event_class = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_clock_class *clock_class = NULL; + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + clock_class = stream_class_get_clock_class(err, stream_class); + goto end; + +error: + BT_PUT(clock_class); +end: + bt_put(stream_class); + bt_put(event_class); + return clock_class; +} + +static +int set_event_clock_value(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event) +{ + struct bt_ctf_clock_class *clock_class = NULL; + struct bt_ctf_clock_value *clock_value = NULL; + int ret; + + clock_class = event_get_clock_class(err, event); + if (!clock_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + clock_value = bt_ctf_event_get_clock_value(event, clock_class); + if (!clock_value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + /* + * We share the same clocks, so we can assign the clock value to the + * writer event. + */ + ret = bt_ctf_event_set_clock_value(writer_event, clock_value); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + bt_put(clock_class); + bt_put(clock_value); + return ret; +} + +static +struct bt_ctf_event *debug_info_copy_event(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event_class *writer_event_class, + struct debug_info *debug_info, + struct debug_info_component *component) +{ + struct bt_ctf_event *writer_event = NULL; + struct bt_ctf_field *field = NULL, *copy_field = NULL; + int ret; + + writer_event = bt_ctf_event_create(writer_event_class); + if (!writer_event) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = set_event_clock_value(err, event, writer_event); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + field = bt_ctf_event_get_header(event); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + ret = ctf_copy_event_header(err, event, writer_event_class, + writer_event, field); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(field); + + /* Optional field, so it can fail silently. */ + field = bt_ctf_event_get_stream_event_context(event); + if (field) { + ret = copy_set_debug_info_stream_event_context(err, + field, event, writer_event, debug_info, + component); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(field); + } + + /* Optional field, so it can fail silently. */ + field = bt_ctf_event_get_event_context(event); + copy_field = bt_ctf_field_copy(field); + if (copy_field) { + ret = bt_ctf_event_set_event_context(writer_event, copy_field); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(copy_field); + } + BT_PUT(field); + + field = bt_ctf_event_get_event_payload(event); + if (!field) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + copy_field = bt_ctf_field_copy(field); + if (copy_field) { + ret = bt_ctf_event_set_event_payload(writer_event, copy_field); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(copy_field); + } + BT_PUT(field); + + goto end; + +error: + BT_PUT(writer_event); +end: + bt_put(copy_field); + bt_put(field); + return writer_event; +} + +BT_HIDDEN +struct bt_ctf_event *debug_info_output_event( + struct debug_info_iterator *debug_it, + struct bt_ctf_event *event) +{ + struct bt_ctf_event_class *event_class = NULL, *writer_event_class = NULL; + struct bt_ctf_stream_class *stream_class = NULL, *writer_stream_class = NULL; + struct bt_ctf_event *writer_event = NULL; + struct bt_ctf_packet *packet = NULL, *writer_packet = NULL; + struct bt_ctf_trace *writer_trace = NULL; + struct debug_info *debug_info; + const char *event_name; + int int_ret; + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + event_name = bt_ctf_event_class_get_name(event_class); + if (!event_name) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_stream_class = g_hash_table_lookup( + debug_it->stream_class_map, + (gpointer) stream_class); + if (!writer_stream_class || !bt_get(writer_stream_class)) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_event_class = get_event_class(debug_it, + writer_stream_class, event_class); + if (!writer_event_class) { + writer_event_class = ctf_copy_event_class(debug_it->err, + event_class); + if (!writer_event_class) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + int_ret = bt_ctf_stream_class_add_event_class( + writer_stream_class, writer_event_class); + if (int_ret) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + } + + writer_trace = bt_ctf_stream_class_get_trace(writer_stream_class); + if (!writer_trace) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + debug_info = get_trace_debug_info(debug_it, writer_trace); + if (debug_info) { + debug_info_handle_event(debug_it->err, event, debug_info); + } + + writer_event = debug_info_copy_event(debug_it->err, event, + writer_event_class, debug_info, + debug_it->debug_info_component); + if (!writer_event) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + fprintf(debug_it->err, "[error] Failed to copy event %s\n", + bt_ctf_event_class_get_name(writer_event_class)); + goto error; + } + + packet = bt_ctf_event_get_packet(event); + if (!packet) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_packet = lookup_packet(debug_it, packet); + if (!writer_packet) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + bt_get(writer_packet); + + int_ret = bt_ctf_event_set_packet(writer_event, writer_packet); + if (int_ret < 0) { + fprintf(debug_it->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + fprintf(debug_it->err, "[error] Failed to append event %s\n", + bt_ctf_event_class_get_name(writer_event_class)); + goto error; + } + + /* Keep the reference on the writer event */ + goto end; + +error: + BT_PUT(writer_event); + +end: + bt_put(writer_trace); + bt_put(writer_packet); + bt_put(packet); + bt_put(writer_event_class); + bt_put(writer_stream_class); + bt_put(stream_class); + bt_put(event_class); + return writer_event; +} diff --git a/plugins/lttng-utils/copy.h b/plugins/lttng-utils/copy.h new file mode 100644 index 00000000..e1441dde --- /dev/null +++ b/plugins/lttng-utils/copy.h @@ -0,0 +1,71 @@ +#ifndef BABELTRACE_PLUGIN_TRIMMER_COPY_H +#define BABELTRACE_PLUGIN_TRIMMER_COPY_H + +/* + * BabelTrace - Copy Trace Structure + * + * Copyright 2017 Julien Desfossez + * + * Author: Julien Desfossez + * + * 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 + +BT_HIDDEN +struct bt_ctf_event *debug_info_output_event(struct debug_info_iterator *debug_it, + struct bt_ctf_event *event); +BT_HIDDEN +struct bt_ctf_packet *debug_info_new_packet(struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet); +BT_HIDDEN +struct bt_ctf_packet *debug_info_close_packet(struct debug_info_iterator *debug_it, + struct bt_ctf_packet *packet); +BT_HIDDEN +struct bt_ctf_stream *debug_info_stream_end(struct debug_info_iterator *debug_it, + struct bt_ctf_stream *stream); + +BT_HIDDEN +int get_stream_event_context_unsigned_int_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint64_t *value); +BT_HIDDEN +int get_stream_event_context_int_field_value(FILE *err, struct bt_ctf_event *event, + const char *field_name, int64_t *value); +BT_HIDDEN +int get_payload_unsigned_int_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint64_t *value); +BT_HIDDEN +int get_payload_int_field_value(FILE *err, struct bt_ctf_event *event, + const char *field_name, int64_t *value); +BT_HIDDEN +int get_payload_string_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + const char **value); +BT_HIDDEN +int get_payload_build_id_field_value(FILE *err, + struct bt_ctf_event *event, const char *field_name, + uint8_t **build_id, uint64_t *build_id_len); + +#endif /* BABELTRACE_PLUGIN_TRIMMER_COPY_H */ diff --git a/plugins/lttng-utils/crc32.c b/plugins/lttng-utils/crc32.c new file mode 100644 index 00000000..e68c0434 --- /dev/null +++ b/plugins/lttng-utils/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/crc32.h b/plugins/lttng-utils/crc32.h new file mode 100644 index 00000000..4a229d63 --- /dev/null +++ b/plugins/lttng-utils/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.c b/plugins/lttng-utils/debug-info.c new file mode 100644 index 00000000..bc8fa6dd --- /dev/null +++ b/plugins/lttng-utils/debug-info.c @@ -0,0 +1,761 @@ +/* + * 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 + * + * 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 "debug-info.h" +#include "bin-info.h" +#include "utils.h" +#include "copy.h" + +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; + + /* + * Hash table of VPIDs (pointer to int64_t) to + * (struct ctf_proc_debug_infos*); 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; + } + + free(debug_info_src->func); + free(debug_info_src->src_path); + free(debug_info_src->bin_path); + 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); + printf_verbose("Failed to lookup source location (err: %i)\n", ret); + } + + if (src_loc) { + debug_info_src->line_no = src_loc->line_no; + + if (src_loc->filename) { + debug_info_src->src_path = 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 = 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 +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) +{ + 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; + } + +end: + return debug_info; +error: + g_free(debug_info); + return NULL; +} + +BT_HIDDEN +void debug_info_destroy(struct debug_info *debug_info) +{ + 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); + } + + g_free(debug_info); +end: + return; +} + +static +void handle_statedump_build_id_event(FILE *err, struct debug_info *debug_info, + struct bt_ctf_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + struct bin_info *bin = NULL; + int ret; + int64_t vpid; + uint64_t baddr; + + ret = get_stream_event_context_int_field_value(err, + event, "_vpid", &vpid); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_payload_unsigned_int_field_value(err, + event, "_baddr", &baddr); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + 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 = get_payload_build_id_field_value(err, event, "_build_id", + &bin->build_id, &bin->build_id_len); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + 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; + + // TODO + // bin_info_set_build_id(bin, build_id, build_id_len); + +end: + return; +} + +static +void handle_statedump_debug_link_event(FILE *err, struct debug_info *debug_info, + struct bt_ctf_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 tmp; + int ret; + + ret = get_stream_event_context_int_field_value(err, event, + "_vpid", &vpid); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_payload_unsigned_int_field_value(err, + event, "_baddr", &baddr); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_payload_unsigned_int_field_value(err, event, "_crc32", &tmp); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + crc32 = (uint32_t) tmp; + + ret = get_payload_string_field_value(err, + event, "_filename", &filename); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + 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(FILE *err, struct debug_info *debug_info, + struct bt_ctf_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; + int ret; + + ret = get_payload_unsigned_int_field_value(err, + event, "_baddr", &baddr); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_payload_unsigned_int_field_value(err, + event, "_memsz", &memsz); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_payload_string_field_value(err, + event, "_path", &path); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + if (has_pic_field) { + uint64_t tmp; + + ret = get_payload_unsigned_int_field_value(err, + event, "_is_pic", &tmp); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + is_pic = (tmp == 1); + } else { + /* + * dlopen has no is_pic field, because the shared + * object is always PIC. + */ + is_pic = true; + } + + ret = get_stream_event_context_int_field_value(err, event, "_vpid", + &vpid); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + if (!path) { + goto end; + } + + if (memsz == 0) { + /* Ignore VDSO. */ + goto end; + } + + 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_statedump_bin_info_event(FILE *err, struct debug_info *debug_info, + struct bt_ctf_event *event) +{ + handle_bin_info_event(err, debug_info, event, true); +} + +static inline +void handle_lib_load_event(FILE *err, struct debug_info *debug_info, + struct bt_ctf_event *event) +{ + handle_bin_info_event(err, debug_info, event, false); +} + +static inline +void handle_lib_unload_event(FILE *err, struct debug_info *debug_info, + struct bt_ctf_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + uint64_t baddr; + int64_t vpid; + gpointer key_ptr = NULL; + int ret; + + ret = get_payload_unsigned_int_field_value(err, + event, "_baddr", &baddr); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = get_stream_event_context_int_field_value(err, event, "_vpid", + &vpid); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + 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_ptr = (gpointer) &baddr; + (void) g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info, + key_ptr); +end: + return; +} + +static +void handle_statedump_start(FILE *err, struct debug_info *debug_info, + struct bt_ctf_event *event) +{ + struct proc_debug_info_sources *proc_dbg_info_src; + int64_t vpid; + int ret; + + ret = get_stream_event_context_int_field_value(err, event, + "_vpid", &vpid); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + 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; +} + +BT_HIDDEN +void debug_info_handle_event(FILE *err, struct bt_ctf_event *event, + struct debug_info *debug_info) +{ + struct bt_ctf_event_class *event_class; + const char *event_name; + GQuark q_event_name; + + if (!debug_info || !event) { + goto end; + } + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + goto end; + } + event_name = bt_ctf_event_class_get_name(event_class); + if (!event_name) { + goto end_put_class; + } + q_event_name = g_quark_try_string(event_name); + + if (q_event_name == debug_info->q_statedump_bin_info) { + /* State dump */ + handle_statedump_bin_info_event(err, 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_lib_load_event(err, debug_info, event); + } else if (q_event_name == debug_info->q_statedump_start) { + /* Start state dump */ + handle_statedump_start(err, debug_info, event); + } else if (q_event_name == debug_info->q_statedump_debug_link) { + /* Debug link info */ + handle_statedump_debug_link_event(err, debug_info, event); + } else if (q_event_name == debug_info->q_statedump_build_id) { + /* Build ID info */ + handle_statedump_build_id_event(err, debug_info, event); + } else if (q_event_name == debug_info-> q_lib_unload) { + handle_lib_unload_event(err, debug_info, event); + } + +end_put_class: + bt_put(event_class); +end: + return; +} diff --git a/plugins/lttng-utils/debug-info.h b/plugins/lttng-utils/debug-info.h new file mode 100644 index 00000000..41618b0a --- /dev/null +++ b/plugins/lttng-utils/debug-info.h @@ -0,0 +1,104 @@ +#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H +#define BABELTRACE_PLUGIN_DEBUG_INFO_H + +/* + * Babeltrace - Debug information Plug-in + * + * Copyright (c) 2015 EfficiOS Inc. + * Copyright (c) 2015 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 +#include +#include + +struct debug_info_component { + FILE *err; + char *arg_debug_info_field_name; + const char *arg_debug_dir; + bool arg_full_path; + const char *arg_target_prefix; +}; + +struct debug_info_iterator { + struct debug_info_component *debug_info_component; + /* Map between struct bt_ctf_trace and struct bt_ctf_writer. */ + GHashTable *trace_map; + /* Map between reader and writer stream. */ + GHashTable *stream_map; + /* Map between reader and writer stream class. */ + GHashTable *stream_class_map; + /* Map between reader and writer stream class. */ + GHashTable *packet_map; + /* Map between a trace_class and its corresponding debug_info. */ + GHashTable *trace_debug_map; + /* Input iterators associated with this output iterator. */ + GPtrArray *input_iterator_group; + struct bt_notification *current_notification; + struct bt_notification_iterator *input_iterator; + FILE *err; +}; + +struct debug_info_source { + /* Strings are owned by debug_info_source. */ + char *func; + uint64_t line_no; + char *src_path; + /* short_src_path points inside src_path, no need to free. */ + const char *short_src_path; + char *bin_path; + /* short_bin_path points inside bin_path, no need to free. */ + const char *short_bin_path; + /* + * Location within the binary. Either absolute (@0x1234) or + * relative (+0x4321). + */ + char *bin_loc; +}; + +BT_HIDDEN +struct debug_info *debug_info_create(struct debug_info_component *comp); + +BT_HIDDEN +void debug_info_destroy(struct debug_info *debug_info); + +BT_HIDDEN +struct debug_info_source *debug_info_query(struct debug_info *debug_info, + int64_t vpid, uint64_t ip); + +BT_HIDDEN +void debug_info_handle_event(FILE *err, struct bt_ctf_event *event, + struct debug_info *debug_info); + +#if 0 +static inline +void trace_debug_info_destroy(struct bt_ctf_trace *trace) +{ + debug_info_destroy(trace->debug_info); +} +#endif + +#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */ diff --git a/plugins/lttng-utils/dwarf.c b/plugins/lttng-utils/dwarf.c new file mode 100644 index 00000000..307bd2aa --- /dev/null +++ b/plugins/lttng-utils/dwarf.c @@ -0,0 +1,369 @@ +/* + * 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_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 = 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 = 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 new file mode 100644 index 00000000..c3d56b78 --- /dev/null +++ b/plugins/lttng-utils/dwarf.h @@ -0,0 +1,226 @@ +#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); + +/** + * 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/plugin.c b/plugins/lttng-utils/plugin.c new file mode 100644 index 00000000..e7cffbd1 --- /dev/null +++ b/plugins/lttng-utils/plugin.c @@ -0,0 +1,482 @@ +/* + * plugin.c + * + * Babeltrace Debug Info Plug-in + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debug-info.h" +#include "copy.h" + +static +void destroy_debug_info_data(struct debug_info_component *debug_info) +{ + free(debug_info->arg_debug_info_field_name); + g_free(debug_info); +} + +static +void destroy_debug_info_component(struct bt_private_component *component) +{ + void *data = bt_private_component_get_user_data(component); + destroy_debug_info_data(data); +} + +static +struct debug_info_component *create_debug_info_component_data(void) +{ + struct debug_info_component *debug_info; + + debug_info = g_new0(struct debug_info_component, 1); + if (!debug_info) { + goto end; + } + debug_info->err = stderr; + +end: + return debug_info; +} + +static +void unref_debug_info(struct debug_info *debug_info) +{ + debug_info_destroy(debug_info); +} + +static +void unref_trace(struct bt_ctf_trace *trace) +{ + bt_put(trace); +} + +static +void unref_stream(struct bt_ctf_stream *stream) +{ + bt_put(stream); +} + +static +void unref_packet(struct bt_ctf_packet *packet) +{ + bt_put(packet); +} + +static +void unref_stream_class(struct bt_ctf_stream_class *stream_class) +{ + bt_put(stream_class); +} + +static +void debug_info_iterator_destroy(struct bt_private_notification_iterator *it) +{ + struct debug_info_iterator *it_data; + + it_data = bt_private_notification_iterator_get_user_data(it); + assert(it_data); + + if (it_data->input_iterator_group) { + g_ptr_array_free(it_data->input_iterator_group, TRUE); + } + bt_put(it_data->current_notification); + bt_put(it_data->input_iterator); + g_hash_table_destroy(it_data->trace_map); + g_hash_table_destroy(it_data->stream_map); + g_hash_table_destroy(it_data->stream_class_map); + g_hash_table_destroy(it_data->packet_map); + g_hash_table_destroy(it_data->trace_debug_map); + g_free(it_data); +} + +static +struct bt_notification *handle_notification(FILE *err, + struct debug_info_iterator *debug_it, + struct bt_notification *notification) +{ + struct bt_notification *new_notification = NULL; + + switch (bt_notification_get_type(notification)) { + case BT_NOTIFICATION_TYPE_PACKET_BEGIN: + { + struct bt_ctf_packet *packet = + bt_notification_packet_begin_get_packet(notification); + struct bt_ctf_packet *writer_packet; + + if (!packet) { + goto end; + } + + writer_packet = debug_info_new_packet(debug_it, packet); + assert(writer_packet); + new_notification = bt_notification_packet_begin_create( + writer_packet); + assert(new_notification); + bt_put(packet); + break; + } + case BT_NOTIFICATION_TYPE_PACKET_END: + { + struct bt_ctf_packet *packet = + bt_notification_packet_end_get_packet(notification); + struct bt_ctf_packet *writer_packet; + + if (!packet) { + goto end; + } + + writer_packet = debug_info_close_packet(debug_it, packet); + assert(writer_packet); + new_notification = bt_notification_packet_end_create( + writer_packet); + assert(new_notification); + bt_put(packet); + bt_put(writer_packet); + break; + } + case BT_NOTIFICATION_TYPE_EVENT: + { + struct bt_ctf_event *event = bt_notification_event_get_event( + notification); + struct bt_ctf_event *writer_event; + struct bt_clock_class_priority_map *cc_prio_map = + bt_notification_event_get_clock_class_priority_map( + notification); + + if (!event) { + goto end; + } + writer_event = debug_info_output_event(debug_it, event); + assert(writer_event); + new_notification = bt_notification_event_create(writer_event, + cc_prio_map); + bt_put(cc_prio_map); + assert(new_notification); + bt_put(event); + bt_put(writer_event); + break; + } + case BT_NOTIFICATION_TYPE_STREAM_END: + { + struct bt_ctf_stream *stream = + bt_notification_stream_end_get_stream(notification); + struct bt_ctf_stream *writer_stream; + + if (!stream) { + goto end; + } + + writer_stream = debug_info_stream_end(debug_it, stream); + assert(writer_stream); + new_notification = bt_notification_stream_end_create( + writer_stream); + assert(new_notification); + bt_put(stream); + bt_put(writer_stream); + break; + } + default: + puts("Unhandled notification type"); + } + +end: + return new_notification; +} + +static +struct bt_notification_iterator_next_return debug_info_iterator_next( + struct bt_private_notification_iterator *iterator) +{ + struct debug_info_iterator *debug_it = NULL; + struct bt_private_component *component = NULL; + struct debug_info_component *debug_info = NULL; + struct bt_notification_iterator *source_it = NULL; + struct bt_notification *notification; + struct bt_notification_iterator_next_return ret = { + .status = BT_NOTIFICATION_ITERATOR_STATUS_OK, + .notification = NULL, + }; + + debug_it = bt_private_notification_iterator_get_user_data(iterator); + assert(debug_it); + + component = bt_private_notification_iterator_get_private_component(iterator); + assert(component); + debug_info = bt_private_component_get_user_data(component); + assert(debug_info); + + source_it = debug_it->input_iterator; + + ret.status = bt_notification_iterator_next(source_it); + if (ret.status != BT_NOTIFICATION_ITERATOR_STATUS_OK) { + goto end; + } + + notification = bt_notification_iterator_get_notification( + source_it); + if (!notification) { + ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + goto end; + } + + ret.notification = handle_notification(debug_info->err, debug_it, + notification); + assert(ret.notification); + bt_put(notification); + +end: + bt_put(component); + return ret; +} + +/* +static +struct bt_notification *debug_info_iterator_get( + struct bt_private_notification_iterator *iterator) +{ + struct debug_info_iterator *debug_it; + + debug_it = bt_private_notification_iterator_get_user_data(iterator); + assert(debug_it); + + if (!debug_it->current_notification) { + enum bt_notification_iterator_status it_ret; + + it_ret = debug_info_iterator_next(iterator); + if (it_ret) { + goto end; + } + } + +end: + return bt_get(debug_it->current_notification); +} +*/ + +static +enum bt_notification_iterator_status debug_info_iterator_init( + struct bt_private_notification_iterator *iterator, + struct bt_private_port *port) +{ + enum bt_notification_iterator_status ret = + BT_NOTIFICATION_ITERATOR_STATUS_OK; + enum bt_notification_iterator_status it_ret; + struct bt_private_port *input_port = NULL; + struct bt_private_connection *connection = NULL; + struct bt_private_component *component = + bt_private_notification_iterator_get_private_component(iterator); + struct debug_info_iterator *it_data = g_new0(struct debug_info_iterator, 1); + + if (!it_data) { + ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; + goto end; + } + + /* Create a new iterator on the upstream component. */ + input_port = bt_private_component_filter_get_input_private_port_by_name( + component, "in"); + assert(input_port); + connection = bt_private_port_get_private_connection(input_port); + assert(connection); + + it_data->input_iterator = bt_private_connection_create_notification_iterator( + connection, NULL); + if (!it_data->input_iterator) { + ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; + goto end; + } + it_data->debug_info_component = (struct debug_info_component *) + bt_private_component_get_user_data(component); + + it_data->err = it_data->debug_info_component->err; + it_data->trace_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_trace); + it_data->stream_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_stream); + it_data->stream_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_stream_class); + it_data->packet_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_packet); + it_data->trace_debug_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_debug_info); + + it_ret = bt_private_notification_iterator_set_user_data(iterator, it_data); + if (it_ret) { + goto end; + } + +end: + bt_put(connection); + bt_put(input_port); + return ret; +} + +static +enum bt_component_status init_from_params( + struct debug_info_component *debug_info_component, + struct bt_value *params) +{ + struct bt_value *value = NULL; + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + + assert(params); + + value = bt_value_map_get(params, "debug-info-field-name"); + if (value) { + enum bt_value_status value_ret; + const char *tmp; + + value_ret = bt_value_string_get(value, &tmp); + if (value_ret) { + ret = BT_COMPONENT_STATUS_INVALID; + printf_error("Failed to retrieve debug-info-field-name value. " + "Expecting a string"); + } + strcpy(debug_info_component->arg_debug_info_field_name, tmp); + bt_put(value); + } else { + debug_info_component->arg_debug_info_field_name = + malloc(strlen("debug_info") + 1); + if (!debug_info_component->arg_debug_info_field_name) { + ret = BT_COMPONENT_STATUS_NOMEM; + printf_error(); + } + sprintf(debug_info_component->arg_debug_info_field_name, + "debug_info"); + } + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + value = bt_value_map_get(params, "debug-dir"); + if (value) { + enum bt_value_status value_ret; + + value_ret = bt_value_string_get(value, + &debug_info_component->arg_debug_dir); + if (value_ret) { + ret = BT_COMPONENT_STATUS_INVALID; + printf_error("Failed to retrieve debug-dir value. " + "Expecting a string"); + } + } + bt_put(value); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + value = bt_value_map_get(params, "target-prefix"); + if (value) { + enum bt_value_status value_ret; + + value_ret = bt_value_string_get(value, + &debug_info_component->arg_target_prefix); + if (value_ret) { + ret = BT_COMPONENT_STATUS_INVALID; + printf_error("Failed to retrieve target-prefix value. " + "Expecting a string"); + } + } + bt_put(value); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + value = bt_value_map_get(params, "full-path"); + if (value) { + enum bt_value_status value_ret; + + value_ret = bt_value_bool_get(value, + &debug_info_component->arg_full_path); + if (value_ret) { + ret = BT_COMPONENT_STATUS_INVALID; + printf_error("Failed to retrieve full-path value. " + "Expecting a boolean"); + } + } + bt_put(value); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + +end: + return ret; +} + +enum bt_component_status debug_info_component_init( + struct bt_private_component *component, struct bt_value *params, + UNUSED_VAR void *init_method_data) +{ + enum bt_component_status ret; + struct debug_info_component *debug_info = create_debug_info_component_data(); + + if (!debug_info) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + ret = bt_private_component_set_user_data(component, debug_info); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + + ret = init_from_params(debug_info, params); +end: + return ret; +error: + destroy_debug_info_data(debug_info); + return ret; +} + +/* Initialize plug-in entry points. */ +BT_PLUGIN_WITH_ID(lttng_utils, "lttng-utils"); +BT_PLUGIN_DESCRIPTION_WITH_ID(lttng_utils, "LTTng utilities"); +BT_PLUGIN_AUTHOR_WITH_ID(lttng_utils, "Julien Desfossez"); +BT_PLUGIN_LICENSE_WITH_ID(lttng_utils, "MIT"); + +BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID(lttng_utils, debug_info, "debug-info", + debug_info_iterator_next); +BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION_WITH_ID(lttng_utils, debug_info, + "Augment compatible events with debugging information."); +BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD_WITH_ID(lttng_utils, + debug_info, debug_info_component_init); +BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(lttng_utils, + debug_info, destroy_debug_info_component); +BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD_WITH_ID( + lttng_utils, debug_info, debug_info_iterator_init); +BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_FINALIZE_METHOD_WITH_ID( + lttng_utils, debug_info, debug_info_iterator_destroy); diff --git a/plugins/lttng-utils/utils.c b/plugins/lttng-utils/utils.c new file mode 100644 index 00000000..80dc87de --- /dev/null +++ b/plugins/lttng-utils/utils.c @@ -0,0 +1,52 @@ +/* + * 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; +} diff --git a/plugins/lttng-utils/utils.h b/plugins/lttng-utils/utils.h new file mode 100644 index 00000000..d2a08c06 --- /dev/null +++ b/plugins/lttng-utils/utils.h @@ -0,0 +1,39 @@ +#ifndef _BABELTRACE_DEBUG_INFO_UTILS_H +#define _BABELTRACE_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 + +/* + * 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); + +#endif /* _BABELTRACE_DEBUG_INFO_UTILS_H */