X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=tests%2Fplugins%2Ftest_bin_info.c;h=d681ef5621abc948c00b6d6266fda030a7c9e4e2;hp=5bf43da020d1f249f20fdb8b5d8d4316e6e92888;hb=cb0775f4167b5115ce71cf41d4d94719d08ef763;hpb=6a2847334d16012b9cfbf11b08aac5535ab3153a diff --git a/tests/plugins/test_bin_info.c b/tests/plugins/test_bin_info.c index 5bf43da0..d681ef56 100644 --- a/tests/plugins/test_bin_info.c +++ b/tests/plugins/test_bin_info.c @@ -5,6 +5,7 @@ * * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation * Copyright (c) 2015 Antoine Busque + * Copyright (c) 2019 Michael Jeanson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,92 +24,234 @@ #include #include #include +#include +#include -#include +#include "common/macros.h" +#include "common/assert.h" #include #include "tap/tap.h" -#define NR_TESTS 36 +#define NR_TESTS 57 + #define SO_NAME "libhello_so" +#define DEBUG_NAME "libhello_so.debug" +#define FUNC_FOO_FILENAME "./libhello.c" +#define FUNC_FOO_PRINTF_NAME_FMT "foo+0x%" PRIx64 +#define FUNC_FOO_NAME_LEN 64 #define DWARF_DIR_NAME "dwarf_full" #define ELF_DIR_NAME "elf_only" #define BUILDID_DIR_NAME "build_id" #define DEBUGLINK_DIR_NAME "debug_link" +/* Lower bound of PIC address mapping */ #define SO_LOW_ADDR 0x400000 -#define SO_MEMSZ 0x400000 -#define FUNC_FOO_ADDR 0x402367 -#define FUNC_FOO_LINE_NO 36 -#define FUNC_FOO_FILENAME "./libhello.c" -#define FUNC_FOO_TP_ADDR 0x402300 -#define FUNC_FOO_TP_LINE_NO 35 -#define FUNC_FOO_TP_FILENAME "./libhello.c" -#define FUNC_FOO_ADDR_ELF 0x402367 -#define FUNC_FOO_ADDR_DBG_LINK 0x402367 -#define FUNC_FOO_NAME "foo+0xf0" -#define FUNC_FOO_NAME_ELF "foo+0xf0" -#define BUILD_ID_LEN 20 - -char *opt_debug_info_dir; -char *opt_debug_info_target_prefix; +/* Size of PIC address mapping */ +#define SO_MEMSZ 0x800000 +/* An address outside the PIC mapping */ +#define SO_INV_ADDR 0x200000 + +#define BUILD_ID_HEX_LEN 20 + +static uint64_t opt_func_foo_addr; +static uint64_t opt_func_foo_printf_offset; +static uint64_t opt_func_foo_printf_line_no; +static uint64_t opt_func_foo_tp_offset; +static uint64_t opt_func_foo_tp_line_no; +static uint64_t opt_debug_link_crc; +static gchar *opt_build_id; +static gchar *opt_debug_info_dir; + +static uint64_t func_foo_printf_addr; +static uint64_t func_foo_tp_addr; +static char func_foo_printf_name[FUNC_FOO_NAME_LEN]; +static uint8_t build_id[BUILD_ID_HEX_LEN]; + +static GOptionEntry entries[] = { + {"foo-addr", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_addr, + "Offset to printf in foo", "0xX"}, + {"printf-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_printf_offset, + "Offset to printf in foo", "0xX"}, + {"printf-lineno", 0, 0, G_OPTION_ARG_INT64, + &opt_func_foo_printf_line_no, "Line number to printf in foo", "N"}, + {"tp-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_offset, + "Offset to tp in foo", "0xX"}, + {"tp-lineno", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_line_no, + "Line number to tp in foo", "N"}, + {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64, &opt_debug_link_crc, + "Debug link CRC", "0xX"}, + {"build-id", 0, 0, G_OPTION_ARG_STRING, &opt_build_id, "Build ID", + "XXXXXXXXXXXXXXX"}, + {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir, + "Debug info directory", NULL}, + {NULL}}; + +static +int build_id_to_bin(void) +{ + int ret, len, i; + + if (opt_build_id == NULL) { + goto error; + } + + len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2); + if (len != (BUILD_ID_HEX_LEN * 2)) { + goto error; + } + + for (i = 0; i < (len / 2); i++) { + ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]); + if (ret != 1) { + goto error; + } + } + + if (i != BUILD_ID_HEX_LEN) { + goto error; + } + + return 0; +error: + return -1; +} + +static +void subtest_has_address(struct bin_info *bin, uint64_t addr) +{ + int ret; + + ret = bin_info_has_address(bin, SO_LOW_ADDR - 1); + ok(ret == 0, "bin_info_has_address - address under SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR); + ok(ret == 1, "bin_info_has_address - lower bound of SO's range"); + + ret = bin_info_has_address(bin, addr); + ok(ret == 1, "bin_info_has_address - address in SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1); + ok(ret == 1, "bin_info_has_address - upper bound of SO's range"); + + ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ); + ok(ret == 0, "bin_info_has_address - address above SO's range"); +} + +static +void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr, + char *func_name) +{ + int ret; + char *_func_name = NULL; + + ret = bin_info_lookup_function_name(bin, addr, &_func_name); + ok(ret == 0, "bin_info_lookup_function_name successful at 0x%x", addr); + if (_func_name) { + ok(strcmp(_func_name, func_name) == 0, + "bin_info_lookup_function_name - correct function name (%s == %s)", + func_name, _func_name); + free(_func_name); + _func_name = NULL; + } else { + skip(1, + "bin_info_lookup_function_name - function name is NULL"); + } + + /* Test function name lookup - erroneous address */ + ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name); + ok(ret == -1 && _func_name == NULL, + "bin_info_lookup_function_name - fail on invalid addr"); + if (_func_name) { + free(_func_name); + } +} + +static +void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr, + uint64_t line_no, char *filename) +{ + int ret; + struct source_location *src_loc = NULL; + + ret = bin_info_lookup_source_location(bin, addr, &src_loc); + ok(ret == 0, "bin_info_lookup_source_location successful at 0x%x", + addr); + if (src_loc) { + ok(src_loc->line_no == line_no, + "bin_info_lookup_source_location - correct line_no (%d == %d)", + line_no, src_loc->line_no); + ok(strcmp(src_loc->filename, filename) == 0, + "bin_info_lookup_source_location - correct filename (%s == %s)", + filename, src_loc->filename); + source_location_destroy(src_loc); + src_loc = NULL; + } else { + fail("bin_info_lookup_source_location - src_loc is NULL"); + fail("bin_info_lookup_source_location - src_loc is NULL"); + } + + /* Test source location lookup - erroneous address */ + ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc); + ok(ret == -1 && src_loc == NULL, + "bin_info_lookup_source_location - fail on invalid addr"); + if (src_loc) { + source_location_destroy(src_loc); + } +} static void test_bin_info_build_id(const char *bin_info_dir) { int ret; char *data_dir, *bin_path; - char *func_name = NULL; struct bin_info *bin = NULL; - struct source_location *src_loc = NULL; struct bt_fd_cache fdc; - uint8_t build_id[BUILD_ID_LEN] = { - 0xcd, 0xd9, 0x8c, 0xdd, 0x87, 0xf7, 0xfe, 0x64, 0xc1, 0x3b, + uint8_t invalid_build_id[BUILD_ID_HEX_LEN] = { + 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd, 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb }; diag("bin-info tests - separate DWARF via build ID"); data_dir = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, NULL); - bin_path = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL); + bin_path = + g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL); if (data_dir == NULL || bin_path == NULL) { exit(EXIT_FAILURE); } ret = bt_fd_cache_init(&fdc); - BT_ASSERT(ret == 0); - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL); - ok(bin != NULL, "bin_info_create successful"); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL); + ok(bin != NULL, "bin_info_create successful (%s)", bin_path); + + /* Test setting invalid build_id */ + ret = bin_info_set_build_id(bin, invalid_build_id, BUILD_ID_HEX_LEN); + ok(ret == -1, "bin_info_set_build_id fail on invalid build_id"); - /* Test setting build_id */ - ret = bin_info_set_build_id(bin, build_id, BUILD_ID_LEN); + /* Test setting correct build_id */ + ret = bin_info_set_build_id(bin, build_id, BUILD_ID_HEX_LEN); ok(ret == 0, "bin_info_set_build_id successful"); + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + /* Test function name lookup (with DWARF) */ - ret = bin_info_lookup_function_name(bin, FUNC_FOO_ADDR, &func_name); - ok(ret == 0, "bin_info_lookup_function_name successful"); - if (func_name) { - ok(strcmp(func_name, FUNC_FOO_NAME) == 0, - "bin_info_lookup_function_name - correct func_name value"); - free(func_name); - } else { - skip(1, "bin_info_lookup_function_name - func_name is NULL"); - } + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); /* Test source location lookup */ - ret = bin_info_lookup_source_location(bin, FUNC_FOO_ADDR, &src_loc); - ok(ret == 0, "bin_info_lookup_source_location successful"); - if (src_loc) { - ok(src_loc->line_no == FUNC_FOO_LINE_NO, - "bin_info_lookup_source_location - correct line_no"); - ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, - "bin_info_lookup_source_location - correct filename"); - source_location_destroy(src_loc); - } else { - skip(2, "bin_info_lookup_source_location - src_loc is NULL"); - } + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); bin_info_destroy(bin); bt_fd_cache_fini(&fdc); @@ -121,57 +264,44 @@ void test_bin_info_debug_link(const char *bin_info_dir) { int ret; char *data_dir, *bin_path; - char *func_name = NULL; struct bin_info *bin = NULL; - struct source_location *src_loc = NULL; - char *dbg_filename = "libhello_so.debug"; - uint32_t crc = 0x289a8fdc; struct bt_fd_cache fdc; diag("bin-info tests - separate DWARF via debug link"); data_dir = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, NULL); - bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME, NULL); + bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME, + NULL); if (data_dir == NULL || bin_path == NULL) { exit(EXIT_FAILURE); } ret = bt_fd_cache_init(&fdc); - BT_ASSERT(ret == 0); - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, - NULL); - ok(bin != NULL, "bin_info_create successful"); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL); + ok(bin != NULL, "bin_info_create successful (%s)", bin_path); /* Test setting debug link */ - ret = bin_info_set_debug_link(bin, dbg_filename, crc); + ret = bin_info_set_debug_link(bin, DEBUG_NAME, opt_debug_link_crc); ok(ret == 0, "bin_info_set_debug_link successful"); + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + /* Test function name lookup (with DWARF) */ - ret = bin_info_lookup_function_name(bin, FUNC_FOO_ADDR_DBG_LINK, - &func_name); - ok(ret == 0, "bin_info_lookup_function_name successful"); - if (func_name) { - ok(strcmp(func_name, FUNC_FOO_NAME) == 0, - "bin_info_lookup_function_name - correct func_name value"); - free(func_name); - } else { - skip(1, "bin_info_lookup_function_name - func_name is NULL"); - } + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); /* Test source location lookup */ - ret = bin_info_lookup_source_location(bin, FUNC_FOO_ADDR_DBG_LINK, - &src_loc); - ok(ret == 0, "bin_info_lookup_source_location successful"); - if (src_loc) { - ok(src_loc->line_no == FUNC_FOO_LINE_NO, - "bin_info_lookup_source_location - correct line_no"); - ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, - "bin_info_lookup_source_location - correct filename"); - source_location_destroy(src_loc); - } else { - skip(2, "bin_info_lookup_source_location - src_loc is NULL"); - } + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); bin_info_destroy(bin); bt_fd_cache_fini(&fdc); @@ -184,7 +314,6 @@ void test_bin_info_elf(const char *bin_info_dir) { int ret; char *data_dir, *bin_path; - char *func_name = NULL; struct bin_info *bin = NULL; struct source_location *src_loc = NULL; struct bt_fd_cache fdc; @@ -199,30 +328,27 @@ void test_bin_info_elf(const char *bin_info_dir) } ret = bt_fd_cache_init(&fdc); - BT_ASSERT(ret == 0); - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL); - ok(bin != NULL, "bin_info_create successful"); - - /* Test function name lookup (with ELF) */ - ret = bin_info_lookup_function_name(bin, FUNC_FOO_ADDR_ELF, &func_name); - ok(ret == 0, "bin_info_lookup_function_name successful"); - if (func_name) { - ok(strcmp(func_name, FUNC_FOO_NAME_ELF) == 0, - "bin_info_lookup_function_name - correct func_name value"); - free(func_name); - func_name = NULL; - } else { - skip(1, "bin_info_lookup_function_name - func_name is NULL"); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); } - /* Test function name lookup - erroneous address */ - ret = bin_info_lookup_function_name(bin, 0, &func_name); - ok(ret == -1 && func_name == NULL, - "bin_info_lookup_function_name - fail on addr not found"); + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL); + ok(bin != NULL, "bin_info_create successful (%s)", bin_path); + + /* Test bin_info_has_address */ + subtest_has_address(bin, func_foo_printf_addr); + + /* Test function name lookup (with ELF) */ + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); /* Test source location location - should fail on ELF only file */ - ret = bin_info_lookup_source_location(bin, FUNC_FOO_ADDR_ELF, &src_loc); - ok(ret == -1, "bin_info_lookup_source_location - fail on ELF only file"); + ret = bin_info_lookup_source_location(bin, func_foo_printf_addr, + &src_loc); + ok(ret == -1, + "bin_info_lookup_source_location - fail on ELF only file"); source_location_destroy(src_loc); bin_info_destroy(bin); @@ -232,92 +358,49 @@ void test_bin_info_elf(const char *bin_info_dir) } static -void test_bin_info(const char *bin_info_dir) +void test_bin_info_bundled(const char *bin_info_dir) { int ret; char *data_dir, *bin_path; - char *func_name = NULL; struct bin_info *bin = NULL; - struct source_location *src_loc = NULL; struct bt_fd_cache fdc; - diag("bin-info tests - DWARF bundled with SO file"); - + diag("bin-info tests - DWARF bundled in SO file"); data_dir = g_build_filename(bin_info_dir, DWARF_DIR_NAME, NULL); - bin_path = g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL); + bin_path = + g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL); if (data_dir == NULL || bin_path == NULL) { exit(EXIT_FAILURE); } ret = bt_fd_cache_init(&fdc); - BT_ASSERT(ret == 0); - bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL); - ok(bin != NULL, "bin_info_create successful"); + if (ret != 0) { + diag("Failed to initialize FD cache"); + exit(EXIT_FAILURE); + } + + bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true, + data_dir, NULL); + ok(bin != NULL, "bin_info_create successful (%s)", bin_path); /* Test bin_info_has_address */ - ret = bin_info_has_address(bin, 0); - ok(ret == 0, "bin_info_has_address - address under so's range"); - ret = bin_info_has_address(bin, SO_LOW_ADDR); - ok(ret == 1, "bin_info_has_address - lower bound of so's range"); - ret = bin_info_has_address(bin, FUNC_FOO_ADDR); - ok(ret == 1, "bin_info_has_address - address in so's range"); - ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1); - ok(ret == 1, "bin_info_has_address - upper bound of so's range"); - ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ); - ok(ret == 0, "bin_info_has_address - address above so's range"); + subtest_has_address(bin, func_foo_printf_addr); /* Test function name lookup (with DWARF) */ - ret = bin_info_lookup_function_name(bin, FUNC_FOO_ADDR, &func_name); - ok(ret == 0, "bin_info_lookup_function_name successful"); - if (func_name) { - ok(strcmp(func_name, FUNC_FOO_NAME) == 0, - "bin_info_lookup_function_name - correct func_name value"); - free(func_name); - func_name = NULL; - } else { - skip(1, "bin_info_lookup_function_name - func_name is NULL"); - } - - /* Test function name lookup - erroneous address */ - ret = bin_info_lookup_function_name(bin, 0, &func_name); - ok(ret == -1 && func_name == NULL, - "bin_info_lookup_function_name - fail on addr not found"); + subtest_lookup_function_name(bin, func_foo_printf_addr, + func_foo_printf_name); /* Test source location lookup */ - ret = bin_info_lookup_source_location(bin, FUNC_FOO_ADDR, &src_loc); - ok(ret == 0, "bin_info_lookup_source_location successful"); - if (src_loc) { - ok(src_loc->line_no == FUNC_FOO_LINE_NO, - "bin_info_lookup_source_location - correct line_no"); - ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, - "bin_info_lookup_source_location - correct filename"); - source_location_destroy(src_loc); - src_loc = NULL; - } else { - skip(2, "bin_info_lookup_source_location - src_loc is NULL"); - } + subtest_lookup_source_location(bin, func_foo_printf_addr, + opt_func_foo_printf_line_no, + FUNC_FOO_FILENAME); /* Test source location lookup - inlined function */ - ret = bin_info_lookup_source_location(bin, FUNC_FOO_TP_ADDR, &src_loc); - ok(ret == 0, - "bin_info_lookup_source_location (inlined func) successful"); - if (src_loc) { - ok(src_loc->line_no == FUNC_FOO_TP_LINE_NO, - "bin_info_lookup_source_location (inlined func) - correct line_no"); - ok(strcmp(src_loc->filename, FUNC_FOO_TP_FILENAME) == 0, - "bin_info_lookup_source_location (inlined func) - correct filename"); - source_location_destroy(src_loc); - src_loc = NULL; - } else { - skip(2, "bin_info_lookup_source_location (inlined func) - src_loc is NULL"); - } - - /* Test source location lookup - erroneous address */ - ret = bin_info_lookup_source_location(bin, 0, &src_loc); - ok(ret == -1 && src_loc == NULL, - "bin_info_lookup_source_location - fail on addr not found"); + subtest_lookup_source_location(bin, func_foo_tp_addr, + opt_func_foo_tp_line_no, + FUNC_FOO_FILENAME); bin_info_destroy(bin); bt_fd_cache_fini(&fdc); @@ -328,20 +411,35 @@ void test_bin_info(const char *bin_info_dir) int main(int argc, char **argv) { int ret; + GError *error = NULL; + GOptionContext *context; - plan_tests(NR_TESTS); + context = g_option_context_new("- bin info test"); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + fprintf(stderr, "option parsing failed: %s\n", error->message); + exit(EXIT_FAILURE); + } - if (argc != 2) { - return EXIT_FAILURE; - } else { - opt_debug_info_dir = argv[1]; + g_snprintf(func_foo_printf_name, FUNC_FOO_NAME_LEN, + FUNC_FOO_PRINTF_NAME_FMT, opt_func_foo_printf_offset); + func_foo_printf_addr = + SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_printf_offset; + func_foo_tp_addr = + SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_tp_offset; + + if (build_id_to_bin()) { + fprintf(stderr, "Failed to parse / missing build id\n"); + exit(EXIT_FAILURE); } + plan_tests(NR_TESTS); + ret = bin_info_init(); ok(ret == 0, "bin_info_init successful"); - test_bin_info(opt_debug_info_dir); test_bin_info_elf(opt_debug_info_dir); + test_bin_info_bundled(opt_debug_info_dir); test_bin_info_build_id(opt_debug_info_dir); test_bin_info_debug_link(opt_debug_info_dir);