flt.lttng-utils.debug-info: cleanup: only print debug message on error
[babeltrace.git] / plugins / lttng-utils / bin-info.c
index 33314bbc5dfa8593bc022bf79cb72ecabf2ca5cb..c810f8c6f8e738bcdf7ba57218b4d71169be95e8 100644 (file)
@@ -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);
@@ -953,11 +1120,19 @@ int bin_info_lookup_function_name(struct bin_info *bin,
        }
 
        if (bin->is_elf_only) {
-               ret = bin_info_lookup_elf_function_name(bin, addr, &_func_name);
-               BT_LOGD("Failed to lookup function name (ELF): ret=%d", ret);
+               ret = bin_info_lookup_elf_function_name(bin, addr,
+                               &_func_name);
+               if (ret) {
+                       BT_LOGD("Failed to lookup function name (ELF): "
+                               "ret=%d", ret);
+               }
        } else {
-               ret = bin_info_lookup_dwarf_function_name(bin, addr, &_func_name);
-               BT_LOGD("Failed to lookup function name (DWARF): ret=%d", ret);
+               ret = bin_info_lookup_dwarf_function_name(bin, addr,
+                               &_func_name);
+               if (ret) {
+                       BT_LOGD("Failed to lookup function name (DWARF): "
+                               "ret=%d", ret);
+               }
        }
 
        *func_name = _func_name;
@@ -970,21 +1145,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 +1402,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 +1485,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)) {
This page took 0.030809 seconds and 4 git commands to generate.