X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Flttng-utils%2Fdebug-info%2Fbin-info.c;h=bad796d225dd7aa43921ca0e49bd3865f857b986;hb=3fadfbc0c91f82c46bd36e6e0657ea93570c9db1;hp=dd42f41cfbcd6301dcfef11e25964a4edb7f1447;hpb=1e638f98d6c4f2c799d4ea4c826f711a59d9f531;p=babeltrace.git diff --git a/plugins/lttng-utils/debug-info/bin-info.c b/plugins/lttng-utils/debug-info/bin-info.c index dd42f41c..bad796d2 100644 --- a/plugins/lttng-utils/debug-info/bin-info.c +++ b/plugins/lttng-utils/debug-info/bin-info.c @@ -42,6 +42,8 @@ #include +#include + #include "bin-info.h" #include "crc32.h" #include "dwarf.h" @@ -88,8 +90,7 @@ struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path, } if (target_prefix) { - bin->elf_path = g_build_path("/", target_prefix, - path, NULL); + bin->elf_path = g_build_filename(target_prefix, path, NULL); } else { bin->elf_path = g_strdup(path); } @@ -165,21 +166,22 @@ int bin_info_set_elf_file(struct bin_info *bin) BT_LOGD("Failed to open %s", bin->elf_path); goto error; } + bin->elf_handle = elf_handle; - elf_file = elf_begin(bt_fd_cache_handle_get_fd(elf_handle), + elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle), ELF_C_READ, NULL); if (!elf_file) { BT_LOGE("elf_begin failed: %s", elf_errmsg(-1)); goto error; } + bin->elf_file = elf_file; + if (elf_kind(elf_file) != ELF_K_ELF) { BT_LOGE("Error: %s is not an ELF object", bin->elf_path); goto error; } - bin->elf_handle = elf_handle; - bin->elf_file = elf_file; return 0; error: @@ -189,39 +191,43 @@ error: } /** - * From a note section data buffer, check if it is a build id note. + * From a note section data struct, check if it is a build id note. * - * @param buf Pointer to a note section + * @param note_data Pointer to a note section * * @returns 1 on match, 0 if `buf` does not contain a * valid build id note */ static -int is_build_id_note_section(uint8_t *buf) +int is_build_id_note_section(Elf_Data *note_data) { + size_t name_offset, desc_offset; + GElf_Nhdr note_header; 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 + /* + * Discard the return value as it contains the size of the note section + * and we don't need it. */ - name_sz = (uint32_t) *buf; - buf += sizeof(name_sz); + (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, + &desc_offset); - buf += sizeof(desc_sz); - - note_type = (uint32_t) *buf; - buf += sizeof(note_type); + /* + * Check the note name length. The name_sz field includes the + * terminating null byte. + */ + if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) { + goto invalid; + } /* Check the note type. */ - if (note_type != NT_GNU_BUILD_ID) { + if (note_header.n_type != NT_GNU_BUILD_ID) { goto invalid; } /* Check the note name. */ - if (memcmp(buf, BUILD_ID_NOTE_NAME, name_sz) != 0) { + if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME, + note_header.n_namesz) != 0) { goto invalid; } @@ -232,46 +238,38 @@ invalid: } /** - * From a build id note section data buffer, check if the build id it contains + * From a build id note section data struct, check if the build id it contains * is identical to the build id passed as parameter. * - * @param file_build_id_note Pointer to the file build id note section. + * @param note_data Pointer to the file build id note section. * @param build_id Pointer to a build id to compare to. * @param build_id_len length of the build id. * * @returns 1 on match, 0 otherwise. */ static -int is_build_id_note_section_matching(uint8_t *file_build_id_note, +int is_build_id_note_section_matching(Elf_Data *note_data, uint8_t *build_id, size_t build_id_len) { - uint32_t name_sz, desc_sz, note_type; + size_t name_offset, desc_offset; + GElf_Nhdr note_header; 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. + * Discard the return value as it contains the size of the note section + * and we don't need it. */ - file_build_id_note += name_sz; + (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset, + &desc_offset); /* * Compare the binary build id with the supplied build id. */ - if (memcmp(build_id, file_build_id_note, build_id_len) == 0) { + if (memcmp(build_id, note_data->d_buf + desc_offset, + build_id_len) == 0) { return 1; } end: @@ -295,8 +293,7 @@ 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; + GElf_Shdr curr_section_hdr; if (!bin->build_id) { goto error; @@ -311,37 +308,35 @@ int is_build_id_matching(struct bin_info *bin) } } - 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) { + Elf_Data *note_data = NULL; + 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) { + if (!gelf_getshdr(curr_section, &curr_section_hdr)) { goto error; } - if (curr_section_hdr->sh_type != SHT_NOTE) { + if (curr_section_hdr.sh_type != SHT_NOTE) { continue; } + /* + * elf_getdata() translates the data to native byte order. + */ note_data = elf_getdata(curr_section, NULL); if (!note_data) { goto error; } /* Check if the note is of the build-id type. */ - is_build_id = is_build_id_note_section(note_data->d_buf); + is_build_id = is_build_id_note_section(note_data); if (!is_build_id) { continue; } @@ -350,14 +345,13 @@ int is_build_id_matching(struct bin_info *bin) * 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); + is_matching = is_build_id_note_section_matching( + note_data, bin->build_id, bin->build_id_len); if (!is_matching) { break; } } error: - g_free(curr_section_hdr); return is_matching; } @@ -507,9 +501,9 @@ 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; + char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL; const char *dbg_dir = NULL; - size_t build_id_file_len; + size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len; if (!bin || !bin->build_id) { goto error; @@ -517,23 +511,49 @@ int bin_info_set_dwarf_info_build_id(struct bin_info *bin) 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; + /* + * The prefix dir is the first byte of the build id, represented in + * lowercase hex as two characters per byte, +1 for '\0'. + */ + build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1); + if (!build_id_prefix_dir) { + goto error; + } + g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]); + + /* + * The build id file is the remaining bytes of the build id, + * represented in lowercase hex, as two characters per byte. + */ + build_id_char_len = (2 * (bin->build_id_len - 1)); + + /* To which the build id suffix is added, +1 for '\0'. */ + build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1; + + /* + * The resulting filename string is the concatenation of the + * hex build id and the suffix. + */ + build_id_file_len = build_id_char_len + build_id_suffix_char_len; build_id_file = g_new0(gchar, build_id_file_len); if (!build_id_file) { goto error; } - g_snprintf(build_id_file, 4, "%02x/", bin->build_id[0]); + /* + * For each byte, starting at offset 1, append two characters + * in lowercase hex. + */ for (i = 1; i < bin->build_id_len; ++i) { - int path_idx = 3 + 2 * (i - 1); + int path_idx = 2 * (i - 1); g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]); } - g_strconcat(build_id_file, BUILD_ID_SUFFIX, NULL); + /* Append the suffix to the generated string, including the '\0'. */ + g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len, + BUILD_ID_SUFFIX); - path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, build_id_file, NULL); + path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL); if (!path) { goto error; } @@ -548,8 +568,9 @@ int bin_info_set_dwarf_info_build_id(struct bin_info *bin) error: ret = -1; end: - free(build_id_file); - free(path); + g_free(build_id_prefix_dir); + g_free(build_id_file); + g_free(path); return ret; } @@ -610,22 +631,17 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) { int ret = 0; const gchar *dbg_dir = NULL; - gchar *bin_dir = NULL, *dir_name = NULL, *path = NULL; + gchar *bin_dir = NULL, *path = NULL; if (!bin || !bin->dbg_link_filename) { goto error; } dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR; - dir_name = g_path_get_dirname(bin->elf_path); - if (!dir_name) { - goto error; - } - - bin_dir = g_strconcat(dir_name, "/", NULL); + bin_dir = g_path_get_dirname(bin->elf_path); /* First look in the executable's dir */ - path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL); + path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL); if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { goto found; @@ -633,7 +649,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) /* If not found, look in .debug subdir */ g_free(path); - path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); + path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL); if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { goto found; @@ -642,7 +658,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) /* Lastly, look under the global debug directory */ g_free(path); - path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); + path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL); if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) { goto found; } @@ -650,7 +666,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin) error: ret = -1; end: - g_free(dir_name); + g_free(bin_dir); g_free(path); return ret; @@ -738,7 +754,6 @@ int bin_info_append_offset_str(const char *base_str, uint64_t low_addr, uint64_t offset; char *_result = NULL; - if (!base_str || !result) { goto error; } @@ -1367,7 +1382,9 @@ error: * @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 + * line number) for the address. Set only if the address + * is found and resolved successfully + * * @returns 0 on success, -1 on failure */ static @@ -1379,7 +1396,7 @@ int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, const char *filename = NULL; Dwarf_Line *line = NULL; Dwarf_Addr line_addr; - int ret, line_no; + int ret = 0, line_no; if (!cu || !src_loc) { goto error; @@ -1392,7 +1409,8 @@ int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, line = dwarf_getsrc_die(die->dwarf_die, addr); if (!line) { - goto error; + /* This is not an error. The caller needs to keep looking. */ + goto end; } ret = dwarf_lineaddr(line, &line_addr); @@ -1420,18 +1438,18 @@ int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr, _src_loc->filename = g_strdup(filename); } - bt_dwarf_die_destroy(die); - if (_src_loc) { *src_loc = _src_loc; } - return 0; + goto end; error: source_location_destroy(_src_loc); + ret = -1; +end: bt_dwarf_die_destroy(die); - return -1; + return ret; } /**