#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO"
#include "logging.h"
+#include <dwarf.h>
+#include <errno.h>
#include <fcntl.h>
-#include <math.h>
+#include <inttypes.h>
#include <libgen.h>
+#include <math.h>
#include <stdio.h>
-#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <dwarf.h>
+
#include <glib.h>
-#include <errno.h>
-#include "dwarf.h"
+
+#include <babeltrace/common-internal.h>
+
#include "bin-info.h"
#include "crc32.h"
+#include "dwarf.h"
#include "utils.h"
/*
}
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_info_create(struct bt_fd_cache *fdc, 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;
+ BT_ASSERT(fdc);
+
if (!path) {
goto error;
}
}
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);
}
bin->build_id = NULL;
bin->build_id_len = 0;
bin->file_build_id_matches = false;
+ bin->fd_cache = fdc;
return bin;
elf_end(bin->elf_file);
- close(bin->elf_fd);
- close(bin->dwarf_fd);
+ bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle);
+ bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle);
g_free(bin);
}
+static
+int bin_info_set_endianness(struct bin_info *bin)
+{
+ int ret, fd;
+ uint8_t e_ident[EI_NIDENT];
+
+ fd = bt_fd_cache_handle_get_fd(bin->elf_handle);
+
+ /*
+ * Read the identification fields of the elf file.
+ */
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ BT_LOGE("Error seeking the beginning of ELF file: %s",
+ strerror(errno));
+ ret = -1;
+ goto error;
+ }
+
+ ret = bt_common_read(fd, e_ident, EI_NIDENT);
+ if (ret < EI_NIDENT) {
+ BT_LOGE_STR("Error reading the ELF identification fields");
+ ret = -1;
+ goto error;
+ }
+
+ /*
+ * Set the endianness.
+ */
+ bin->endianness = e_ident[EI_DATA];
+ ret = 0;
+
+error:
+ return ret;
+}
+
/**
* Initialize the ELF file for a given executable.
*
static
int bin_info_set_elf_file(struct bin_info *bin)
{
- int elf_fd = -1;
+ struct bt_fd_cache_handle *elf_handle = NULL;
Elf *elf_file = NULL;
+ int ret;
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);
+ elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path);
+ if (!elf_handle) {
+ BT_LOGD("Failed to open %s", bin->elf_path);
+ goto error;
+ }
+ bin->elf_handle = elf_handle;
+
+ ret = bin_info_set_endianness(bin);
+ if (ret) {
goto error;
}
- elf_file = elf_begin(elf_fd, ELF_C_READ, NULL);
+ 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\n", elf_errmsg(-1));
+ 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\n",
- bin->elf_path);
+ BT_LOGE("Error: %s is not an ELF object", 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;
- }
+ bt_fd_cache_put_handle(bin->fd_cache, elf_handle);
elf_end(elf_file);
- return elf_fd;
+ return -1;
}
/**
* - Note type
*/
name_sz = (uint32_t) *buf;
+
+ /*
+ * Check the note name length. The name_sz field includes the
+ * terminating null byte.
+ */
+ if (name_sz != sizeof(BUILD_ID_NOTE_NAME)) {
+ goto invalid;
+ }
+
buf += sizeof(name_sz);
+ /* Ignore the note description size. */
buf += sizeof(desc_sz);
note_type = (uint32_t) *buf;
{
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;
}
}
- 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 *file_note_data = NULL;
+ Elf_Data native_note_data;
+
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;
}
- note_data = elf_getdata(curr_section, NULL);
- if (!note_data) {
+ file_note_data = elf_getdata(curr_section, NULL);
+ if (!file_note_data) {
goto error;
}
+ /*
+ * Prepare the destination buffer to receive the natively
+ * ordered note. The `d_buf`, `d_size`, and `d_version` fields
+ * of the destination structure must be set before invoking the
+ * `gelf_xlatetom()` function.
+ */
+ native_note_data.d_buf = g_new0(uint8_t, file_note_data->d_size);
+ BT_ASSERT(native_note_data.d_buf);
+
+ native_note_data.d_size = file_note_data->d_size;
+ native_note_data.d_version = file_note_data->d_version;
+
+ /* Translate the note data buffer to the host endianness. */
+ gelf_xlatetom(bin->elf_file, &native_note_data, file_note_data,
+ bin->endianness);
+
/* 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(native_note_data.d_buf);
if (!is_build_id) {
+ g_free(native_note_data.d_buf);
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);
+ is_matching = is_build_id_note_section_matching(
+ native_note_data.d_buf, bin->build_id,
+ bin->build_id_len);
+ g_free(native_note_data.d_buf);
if (!is_matching) {
break;
}
}
error:
- g_free(curr_section_hdr);
return is_matching;
}
static
int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
{
- int fd = -1, ret = 0;
+ int ret = 0;
+ struct bt_fd_cache_handle *dwarf_handle = NULL;
struct bt_dwarf_cu *cu = NULL;
Dwarf *dwarf_info = NULL;
goto error;
}
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- fd = -errno;
+ dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+ if (!dwarf_handle) {
goto error;
}
- dwarf_info = dwarf_begin(fd, DWARF_C_READ);
+ dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle),
+ DWARF_C_READ);
if (!dwarf_info) {
goto error;
}
goto error;
}
- bin->dwarf_fd = fd;
+ bin->dwarf_handle = dwarf_handle;
bin->dwarf_path = g_strdup(path);
if (!bin->dwarf_path) {
goto error;
return 0;
error:
- if (fd >= 0) {
- close(fd);
- fd = -1;
- }
+ bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle);
dwarf_end(dwarf_info);
g_free(dwarf_info);
free(cu);
- return fd;
+ return -1;
}
/**
int i = 0, ret = 0;
char *path = 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;
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_char_len = (2 * bin->build_id_len) + 1;
+ build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1;
+ 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[path_idx], 3, "%02x", bin->build_id[i]);
}
- g_strconcat(build_id_file, BUILD_ID_SUFFIX, NULL);
+ 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_file, NULL);
if (!path) {
goto error;
}
* 0 otherwise
*/
static
-int is_valid_debug_file(char *path, uint32_t crc)
+int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc)
{
- int ret = 0, fd = -1;
+ int ret = 0;
+ struct bt_fd_cache_handle *debug_handle = NULL;
uint32_t _crc = 0;
if (!path) {
- goto end_noclose;
+ goto end;
}
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- goto end_noclose;
+ debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+ if (!debug_handle) {
+ goto end;
}
- ret = crc32(fd, &_crc);
+ ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc);
if (ret) {
ret = 0;
goto end;
ret = (crc == _crc);
end:
- close(fd);
-end_noclose:
+ bt_fd_cache_put_handle(bin->fd_cache, debug_handle);
return ret;
}
/* First look in the executable's dir */
path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL);
- if (is_valid_debug_file(path, bin->dbg_link_crc)) {
+ if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
}
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)) {
+ if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
}
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)) {
+ if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
}
error:
ret = -1;
end:
+ g_free(bin_dir);
g_free(dir_name);
g_free(path);
uint64_t offset;
char *_result = NULL;
-
if (!base_str || !result) {
goto error;
}
if (!bin->dwarf_info && !bin->is_elf_only) {
ret = bin_info_set_dwarf_info(bin);
if (ret) {
- BT_LOGD_STR("Failed to set bin dwarf info, falling back to ELF lookup.");
+ BT_LOGD_STR("Failed to set bin dwarf info, falling "
+ "back to ELF lookup.");
/* Failed to set DWARF info, fallback to ELF. */
bin->is_elf_only = true;
}
* @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
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);
*src_loc = _src_loc;
}
+end:
return 0;
error: