X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Flttng-utils%2Fbin-info.c;h=daf61e2cf8fb4bdbf87a439bcd87bc48ffc45247;hb=2638950d97cea60116c550cdfb9fd7bbe5cf6b84;hp=33314bbc5dfa8593bc022bf79cb72ecabf2ca5cb;hpb=d30bb635be214aec655db655e5d03ce2e3fa0d5d;p=babeltrace.git diff --git a/plugins/lttng-utils/bin-info.c b/plugins/lttng-utils/bin-info.c index 33314bbc..daf61e2c 100644 --- a/plugins/lttng-utils/bin-info.c +++ b/plugins/lttng-utils/bin-info.c @@ -51,6 +51,7 @@ * character). */ #define ADDR_STR_LEN 20 +#define BUILD_ID_NOTE_NAME "GNU" BT_HIDDEN int bin_info_init(void) @@ -86,7 +87,7 @@ struct bin_info *bin_info_create(const char *path, uint64_t low_addr, bin->elf_path = g_build_path("/", target_prefix, path, NULL); } else { - bin->elf_path = strdup(path); + bin->elf_path = g_strdup(path); } if (!bin->elf_path) { @@ -94,7 +95,7 @@ struct bin_info *bin_info_create(const char *path, uint64_t low_addr, } if (debug_info_dir) { - bin->debug_info_dir = strdup(debug_info_dir); + bin->debug_info_dir = g_strdup(debug_info_dir); if (!bin->debug_info_dir) { goto error; } @@ -104,6 +105,9 @@ struct bin_info *bin_info_create(const char *path, uint64_t low_addr, bin->memsz = memsz; bin->low_addr = low_addr; bin->high_addr = bin->low_addr + bin->memsz; + bin->build_id = NULL; + bin->build_id_len = 0; + bin->file_build_id_matches = false; return bin; @@ -121,11 +125,11 @@ void bin_info_destroy(struct bin_info *bin) dwarf_end(bin->dwarf_info); - free(bin->debug_info_dir); - free(bin->elf_path); - free(bin->dwarf_path); + g_free(bin->debug_info_dir); + g_free(bin->elf_path); + g_free(bin->dwarf_path); g_free(bin->build_id); - free(bin->dbg_link_filename); + g_free(bin->dbg_link_filename); elf_end(bin->elf_file); @@ -135,6 +139,227 @@ void bin_info_destroy(struct bin_info *bin) g_free(bin); } +/** + * Initialize the ELF file for a given executable. + * + * @param bin bin_info instance + * @returns 0 on success, negative value on error. + */ +static +int bin_info_set_elf_file(struct bin_info *bin) +{ + int elf_fd = -1; + Elf *elf_file = NULL; + + if (!bin) { + goto error; + } + + elf_fd = open(bin->elf_path, O_RDONLY); + if (elf_fd < 0) { + elf_fd = -errno; + BT_LOGE("Failed to open %s\n", bin->elf_path); + goto error; + } + + elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); + if (!elf_file) { + BT_LOGE("elf_begin failed: %s\n", elf_errmsg(-1)); + goto error; + } + + if (elf_kind(elf_file) != ELF_K_ELF) { + BT_LOGE("Error: %s is not an ELF object\n", + bin->elf_path); + goto error; + } + + bin->elf_fd = elf_fd; + bin->elf_file = elf_file; + return 0; + +error: + if (elf_fd >= 0) { + close(elf_fd); + elf_fd = -1; + } + elf_end(elf_file); + return elf_fd; +} + +/** + * From a note section data buffer, check if it is a build id note. + * + * @param buf Pointer to a note section + * + * @returns 1 on match, 0 if `buf` does not contain a + * valid build id note + */ +static +int is_build_id_note_section(uint8_t *buf) +{ + int ret = 0; + uint32_t name_sz, desc_sz, note_type; + + /* The note section header has 3 32bit integer for the following: + * - Section name size + * - Description size + * - Note type + */ + name_sz = (uint32_t) *buf; + buf += sizeof(name_sz); + + buf += sizeof(desc_sz); + + note_type = (uint32_t) *buf; + buf += sizeof(note_type); + + /* Check the note type. */ + if (note_type != NT_GNU_BUILD_ID) { + goto invalid; + } + + /* Check the note name. */ + if (memcmp(buf, BUILD_ID_NOTE_NAME, name_sz) != 0) { + goto invalid; + } + + ret = 1; + +invalid: + return ret; +} + +/** + * From a build id note section data buffer, check if the build id it contains + * is identical to the build id passed as parameter. + * + * @param file_build_id_note Pointer to the file build id note section. + * @param build_id Pointer to a build id to compare to. + * @param build_id_len length of the build id. + * + * @returns 1 on match, 0 otherwise. + */ +static +int is_build_id_note_section_matching(uint8_t *file_build_id_note, + uint8_t *build_id, size_t build_id_len) +{ + uint32_t name_sz, desc_sz, note_type; + + if (build_id_len <= 0) { + goto end; + } + + /* The note section header has 3 32bit integer for the following: + * - Section name size + * - Description size + * - Note type + */ + name_sz = (uint32_t) *file_build_id_note; + file_build_id_note += sizeof(name_sz); + file_build_id_note += sizeof(desc_sz); + file_build_id_note += sizeof(note_type); + + /* + * Move the pointer pass the name char array. This corresponds to the + * beginning of the description section. The description is the build + * id in the case of a build id note. + */ + file_build_id_note += name_sz; + + /* + * Compare the binary build id with the supplied build id. + */ + if (memcmp(build_id, file_build_id_note, build_id_len) == 0) { + return 1; + } +end: + return 0; +} + +/** + * Checks if the build id stored in `bin` (bin->build_id) is matching the build + * id of the ondisk file (bin->elf_file). + * + * @param bin bin_info instance + * @param build_id build id to compare ot the on disk file + * @param build_id_len length of the build id + * + * @returns 1 on if the build id of stored in `bin` matches + * the build id of the ondisk file. + * 0 on if they are different or an error occured. + */ +static +int is_build_id_matching(struct bin_info *bin) +{ + int ret, is_build_id, is_matching = 0; + Elf_Scn *curr_section = NULL, *next_section = NULL; + Elf_Data *note_data = NULL; + GElf_Shdr *curr_section_hdr = NULL; + + if (!bin->build_id) { + goto error; + } + + /* Set ELF file if it hasn't been accessed yet. */ + if (!bin->elf_file) { + ret = bin_info_set_elf_file(bin); + if (ret) { + /* Failed to set ELF file. */ + goto error; + } + } + + curr_section_hdr = g_new0(GElf_Shdr, 1); + if (!curr_section_hdr) { + goto error; + } + + next_section = elf_nextscn(bin->elf_file, curr_section); + if (!next_section) { + goto error; + } + + while (next_section) { + curr_section = next_section; + next_section = elf_nextscn(bin->elf_file, curr_section); + + curr_section_hdr = gelf_getshdr(curr_section, curr_section_hdr); + + if (!curr_section_hdr) { + goto error; + } + + if (curr_section_hdr->sh_type != SHT_NOTE) { + continue; + } + + note_data = elf_getdata(curr_section, NULL); + if (!note_data) { + goto error; + } + + /* Check if the note is of the build-id type. */ + is_build_id = is_build_id_note_section(note_data->d_buf); + if (!is_build_id) { + continue; + } + + /* + * Compare the build id of the on-disk file and + * the build id recorded in the trace. + */ + is_matching = is_build_id_note_section_matching(note_data->d_buf, + bin->build_id, bin->build_id_len); + if (!is_matching) { + break; + } + } +error: + g_free(curr_section_hdr); + return is_matching; +} + BT_HIDDEN int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, size_t build_id_len) @@ -143,7 +368,8 @@ int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, goto error; } - bin->build_id = malloc(build_id_len); + /* Set the build id. */ + bin->build_id = g_new0(uint8_t, build_id_len); if (!bin->build_id) { goto error; } @@ -151,6 +377,17 @@ int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, memcpy(bin->build_id, build_id, build_id_len); bin->build_id_len = build_id_len; + /* + * Check if the file found on the file system has the same build id + * that what was recorded in the trace. + */ + bin->file_build_id_matches = is_build_id_matching(bin); + if (!bin->file_build_id_matches) { + BT_LOGD_STR("Supplied Build ID does not match Build ID of the " + "binary or library found on the file system."); + goto error; + } + /* * Reset the is_elf_only flag in case it had been set * previously, because we might find separate debug info using @@ -161,7 +398,6 @@ int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id, return 0; error: - return -1; } @@ -173,7 +409,7 @@ int bin_info_set_debug_link(struct bin_info *bin, const char *filename, goto error; } - bin->dbg_link_filename = strdup(filename); + bin->dbg_link_filename = g_strdup(filename); if (!bin->dbg_link_filename) { goto error; } @@ -239,7 +475,7 @@ int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path) } bin->dwarf_fd = fd; - bin->dwarf_path = strdup(path); + bin->dwarf_path = g_strdup(path); if (!bin->dwarf_path) { goto error; } @@ -280,23 +516,23 @@ int bin_info_set_dwarf_info_build_id(struct bin_info *bin) goto error; } - dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR; + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; /* 2 characters per byte printed in hex, +1 for '/' and +1 for '\0' */ build_id_file_len = (2 * bin->build_id_len) + 1 + strlen(BUILD_ID_SUFFIX) + 1; - build_id_file = malloc(build_id_file_len); + build_id_file = g_new0(gchar, build_id_file_len); if (!build_id_file) { goto error; } - snprintf(build_id_file, 4, "%02x/", bin->build_id[0]); + g_snprintf(build_id_file, 4, "%02x/", bin->build_id[0]); for (i = 1; i < bin->build_id_len; ++i) { int path_idx = 3 + 2 * (i - 1); - snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); + g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); } - strcat(build_id_file, BUILD_ID_SUFFIX); + g_strconcat(build_id_file, BUILD_ID_SUFFIX, NULL); path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, build_id_file, NULL); if (!path) { @@ -364,7 +600,7 @@ end_noclose: /** * Try to set the dwarf_info for a given bin_info instance via the - * build ID method. + * debug-link method. * * @param bin bin_info instance for which to retrieve the * DWARF info via debug link @@ -374,60 +610,40 @@ 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; + const gchar *dbg_dir = NULL; + gchar *bin_dir = NULL, *dir_name = NULL, *path = NULL; if (!bin || !bin->dbg_link_filename) { goto error; } - dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR; - + dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; dir_name = g_path_get_dirname(bin->elf_path); if (!dir_name) { goto error; } - /* bin_dir is just dir_name with a trailing slash */ - bin_dir = g_new0(char, 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 = g_new0(char, max_path_len); - if (!path) { - goto error; - } + bin_dir = g_strconcat(dir_name, "/", NULL); /* First look in the executable's dir */ - strcpy(path, bin_dir); - strcat(path, bin->dbg_link_filename); + path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL); if (is_valid_debug_file(path, bin->dbg_link_crc)) { goto found; } /* If not found, look in .debug subdir */ - strcpy(path, bin_dir); - strcat(path, DEBUG_SUBDIR); - strcat(path, bin->dbg_link_filename); + g_free(path); + path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); if (is_valid_debug_file(path, bin->dbg_link_crc)) { goto found; } /* Lastly, look under the global debug directory */ - strcpy(path, dbg_dir); - strcat(path, bin_dir); - strcat(path, bin->dbg_link_filename); + g_free(path); + path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); if (is_valid_debug_file(path, bin->dbg_link_crc)) { goto found; } @@ -437,7 +653,6 @@ error: end: g_free(dir_name); g_free(path); - g_free(bin_dir); return ret; @@ -490,54 +705,6 @@ 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; - BT_LOGD("Failed to open ELF file: path=\"%s\"", bin->elf_path); - goto error; - } - - elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); - if (!elf_file) { - BT_LOGD("elf_begin() failed: %s.", elf_errmsg(-1)); - goto error; - } - - if (elf_kind(elf_file) != ELF_K_ELF) { - BT_LOGD("ELF file is not an ELF object: path=\"%s\"", - 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) { @@ -569,10 +736,9 @@ 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; @@ -580,17 +746,10 @@ int bin_info_append_offset_str(const char *base_str, uint64_t low_addr, offset = high_addr - low_addr; - _result = malloc(strlen(base_str) + ADDR_STR_LEN); + _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset); 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; @@ -930,6 +1089,14 @@ int bin_info_lookup_function_name(struct bin_info *bin, goto error; } + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + /* Set DWARF info if it hasn't been accessed yet. */ if (!bin->dwarf_info && !bin->is_elf_only) { ret = bin_info_set_dwarf_info(bin); @@ -970,21 +1137,28 @@ error: 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; + gchar *_bin_loc = NULL; if (!bin || !bin_loc) { goto error; } + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + if (bin->is_pic) { addr -= bin->low_addr; - ret = asprintf(&_bin_loc, "+%#0" PRIx64, addr); + _bin_loc = g_strdup_printf("+%#0" PRIx64, addr); } else { - ret = asprintf(&_bin_loc, "@%#0" PRIx64, addr); + _bin_loc = g_strdup_printf("@%#0" PRIx64, addr); } - if (ret == -1 || !_bin_loc) { + if (!_bin_loc) { goto error; } @@ -1220,7 +1394,7 @@ int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, } _src_loc->line_no = line_no; - _src_loc->filename = strdup(filename); + _src_loc->filename = g_strdup(filename); } bt_dwarf_die_destroy(die); @@ -1303,6 +1477,14 @@ int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr, goto error; } + /* + * If the bin_info has a build id but it does not match the build id + * that was found on the file system, return an error. + */ + if (bin->build_id && !bin->file_build_id_matches) { + goto error; + } + /* Set DWARF info if it hasn't been accessed yet. */ if (!bin->dwarf_info && !bin->is_elf_only) { if (bin_info_set_dwarf_info(bin)) {